Merge remote-tracking branch 'origin/master' into hermes/hermes-1e775b03

# Conflicts:
#	server-rs/crates/api-server/src/app.rs
#	server-rs/crates/api-server/src/creation_entry_config.rs
#	server-rs/crates/api-server/src/puzzle.rs
#	server-rs/crates/spacetime-client/src/lib.rs
#	src/components/platform-entry/PlatformEntryFlowShellImpl.tsx
This commit is contained in:
2026-05-14 19:17:17 +08:00
495 changed files with 40663 additions and 5654 deletions

View File

@@ -0,0 +1,351 @@
import { Buffer } from 'node:buffer';
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const skillRoot = path.resolve(__dirname, '..');
const repoRoot = path.resolve(skillRoot, '..', '..', '..');
const defaultOutDir = path.join(repoRoot, 'public', 'anthro-cat-illustrations');
const defaultTimeoutMs = 180000;
const prompts = [
{
id: 'cat-barista',
title: '咖啡师猫咪',
subject:
'一只奶油色猫咪像人一样双足站立,穿深绿色围裙,在温暖咖啡馆吧台前专注拉花,爪子扶着咖啡杯,蓬松尾巴自然弯起,童书级精致插画,柔和自然光,主体清晰。',
},
{
id: 'cat-detective',
title: '侦探猫咪',
subject:
'一只黑白猫咪像侦探一样双足站在雨后街角,穿短风衣和小帽子,单爪拿放大镜,另一只爪插兜,路灯和湿润石板路反光,电影感但可爱,插画风格。',
},
{
id: 'cat-dancer',
title: '舞者猫咪',
subject:
'一只橘猫以拟人舞者姿态单脚旋转,穿轻盈舞台披肩,前爪展开,尾巴形成优雅弧线,背景是暖色小剧场灯光,动作灵动,精致插画。',
},
{
id: 'cat-knight',
title: '骑士猫咪',
subject:
'一只银灰猫咪像小骑士一样站在苔藓石台上,披短斗篷,双爪握着细剑指向地面,姿态勇敢但可亲,远处森林微光,奇幻插画风格。',
},
{
id: 'cat-painter',
title: '画家猫咪',
subject:
'一只三花猫咪双足站在画架前,穿宽松蓝色工作衫,一爪拿画笔一爪托调色盘,鼻尖有颜料点,窗边画室阳光明亮,温柔手绘插画。',
},
{
id: 'cat-astronaut',
title: '宇航员猫咪',
subject:
'一只白猫咪以拟人宇航员姿态站在月面,透明头盔内露出猫脸,尾巴在宇航服后轻轻翘起,爪子向远处蓝色星球敬礼,梦幻插画风格。',
},
];
const args = new Map();
for (let index = 2; index < process.argv.length; index += 1) {
const raw = process.argv[index];
if (raw.startsWith('--')) {
const next = process.argv[index + 1];
if (next && !next.startsWith('--')) {
args.set(raw, next);
index += 1;
} else {
args.set(raw, true);
}
}
}
function readDotenv(fileName) {
const filePath = path.join(repoRoot, fileName);
if (!existsSync(filePath)) {
return {};
}
const values = {};
for (const line of readFileSync(filePath, 'utf8').split(/\r?\n/u)) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) {
continue;
}
const match = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/u.exec(trimmed);
if (!match) {
continue;
}
let value = match[2].trim();
if (
(value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))
) {
value = value.slice(1, -1);
}
values[match[1]] = value;
}
return values;
}
function resolveEnv() {
const loaded = {
...readDotenv('.env.example'),
...readDotenv('.env.local'),
...readDotenv('.env.secrets.local'),
...process.env,
};
return {
baseUrl: String(loaded.VECTOR_ENGINE_BASE_URL || '')
.trim()
.replace(/\/+$/u, ''),
apiKey: String(loaded.VECTOR_ENGINE_API_KEY || '').trim(),
timeoutMs: Number.parseInt(
String(loaded.VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS || defaultTimeoutMs),
10,
),
};
}
function buildVectorEngineImagesGenerationUrl(baseUrl) {
return baseUrl.endsWith('/v1')
? `${baseUrl}/images/generations`
: `${baseUrl}/v1/images/generations`;
}
function buildPrompt(entry) {
return [
'请生成一张高清 1:1 方形插画。',
`画面主体:${entry.subject}`,
'要求:猫咪保留清晰猫脸、猫耳、猫尾和毛发质感,但身体姿态像人一样自然;构图完整,角色占画面主体,适合作为项目插画素材。',
'避免文字、水印、边框、按钮、UI 元素、低清晰度、过度写实恐怖感、畸形肢体、多余手指。',
].join('');
}
function collectStringsByKey(value, targetKey, output) {
if (Array.isArray(value)) {
value.forEach((entry) => collectStringsByKey(entry, targetKey, output));
return;
}
if (!value || typeof value !== 'object') {
return;
}
for (const [key, nested] of Object.entries(value)) {
if (key === targetKey) {
if (typeof nested === 'string' && nested.trim()) {
output.push(nested.trim());
}
if (Array.isArray(nested)) {
nested.forEach((entry) => {
if (typeof entry === 'string' && entry.trim()) {
output.push(entry.trim());
}
});
}
}
collectStringsByKey(nested, targetKey, output);
}
}
function extractImageUrls(payload) {
const urls = [];
collectStringsByKey(payload, 'url', urls);
collectStringsByKey(payload, 'image', urls);
collectStringsByKey(payload, 'image_url', urls);
return [...new Set(urls)].filter((url) => /^https?:\/\//u.test(url));
}
function extractBase64Images(payload) {
const values = [];
collectStringsByKey(payload, 'b64_json', values);
return values;
}
function inferExtensionFromContentType(contentType) {
const normalized = contentType.split(';')[0]?.trim().toLowerCase();
if (normalized === 'image/png') {
return 'png';
}
if (normalized === 'image/webp') {
return 'webp';
}
if (normalized === 'image/gif') {
return 'gif';
}
return 'jpg';
}
function inferExtensionFromBytes(bytes) {
if (bytes.subarray(0, 8).equals(Buffer.from('\x89PNG\r\n\x1A\n', 'binary'))) {
return 'png';
}
if (bytes.subarray(0, 3).equals(Buffer.from([0xff, 0xd8, 0xff]))) {
return 'jpg';
}
if (
bytes.subarray(0, 4).toString('ascii') === 'RIFF' &&
bytes.subarray(8, 12).toString('ascii') === 'WEBP'
) {
return 'webp';
}
return 'png';
}
async function fetchJson(url, options, timeoutMs) {
const abortController = new AbortController();
const timer = setTimeout(() => abortController.abort(), timeoutMs);
try {
const response = await fetch(url, {
...options,
signal: abortController.signal,
});
const text = await response.text();
if (!response.ok) {
throw new Error(`VectorEngine ${response.status}: ${text.slice(0, 600)}`);
}
return JSON.parse(text);
} catch (error) {
if (error?.name === 'AbortError') {
throw new Error(`VectorEngine request timed out after ${timeoutMs}ms`);
}
throw error;
} finally {
clearTimeout(timer);
}
}
async function downloadUrl(url, timeoutMs) {
const abortController = new AbortController();
const timer = setTimeout(() => abortController.abort(), timeoutMs);
try {
const response = await fetch(url, { signal: abortController.signal });
if (!response.ok) {
throw new Error(`download ${response.status}`);
}
const bytes = Buffer.from(await response.arrayBuffer());
return {
bytes,
extension: inferExtensionFromContentType(
response.headers.get('content-type') || 'image/jpeg',
),
};
} catch (error) {
if (error?.name === 'AbortError') {
throw new Error(`Generated image download timed out after ${timeoutMs}ms`);
}
throw error;
} finally {
clearTimeout(timer);
}
}
async function generateOne(env, entry, outDir) {
const requestBody = {
model: 'gpt-image-2-all',
prompt: buildPrompt(entry),
n: 1,
size: '1024x1024',
};
const payload = await fetchJson(
buildVectorEngineImagesGenerationUrl(env.baseUrl),
{
method: 'POST',
headers: {
Authorization: `Bearer ${env.apiKey}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(requestBody),
},
env.timeoutMs,
);
const urls = extractImageUrls(payload);
const b64Images = extractBase64Images(payload);
let image;
if (urls[0]) {
image = await downloadUrl(urls[0], env.timeoutMs);
} else if (b64Images[0]) {
const bytes = Buffer.from(b64Images[0], 'base64');
image = {
bytes,
extension: inferExtensionFromBytes(bytes),
};
} else {
throw new Error(`VectorEngine returned no image for ${entry.id}`);
}
mkdirSync(outDir, { recursive: true });
const outputPath = path.join(outDir, `${entry.id}.${image.extension}`);
writeFileSync(outputPath, image.bytes);
return outputPath;
}
const dryRun = args.has('--dry-run') || !args.has('--live');
const outDir = path.resolve(String(args.get('--out-dir') || defaultOutDir));
const limit = Number.parseInt(String(args.get('--limit') || '0'), 10);
const selectedPrompts = limit > 0 ? prompts.slice(0, limit) : prompts;
if (dryRun) {
const env = resolveEnv();
console.log(
JSON.stringify(
{
mode: 'dry-run',
outDir,
count: selectedPrompts.length,
hasBaseUrl: Boolean(env.baseUrl),
hasApiKey: Boolean(env.apiKey),
requests: selectedPrompts.map((entry) => ({
id: entry.id,
title: entry.title,
body: {
model: 'gpt-image-2-all',
prompt: buildPrompt(entry),
n: 1,
size: '1024x1024',
},
})),
},
null,
2,
),
);
process.exit(0);
}
const env = resolveEnv();
if (!env.baseUrl || !env.apiKey) {
console.error(
JSON.stringify({
ok: false,
error: 'Missing VECTOR_ENGINE_BASE_URL or VECTOR_ENGINE_API_KEY',
hasBaseUrl: Boolean(env.baseUrl),
hasApiKey: Boolean(env.apiKey),
}),
);
process.exit(1);
}
const generated = [];
for (const entry of selectedPrompts) {
console.log(`Generating ${entry.id}...`);
generated.push(await generateOne(env, entry, outDir));
}
console.log(
JSON.stringify(
{
ok: true,
count: generated.length,
files: generated,
},
null,
2,
),
);

5
.env Normal file
View File

@@ -0,0 +1,5 @@
# 微信小程序 web-view 登录配置。
# 留空时不覆盖已有微信网页 OAuth 配置;正式联调时再填小程序 AppID / AppSecret。
WECHAT_MINI_PROGRAM_APP_ID=""
WECHAT_MINI_PROGRAM_APP_SECRET=""
WECHAT_JS_CODE_SESSION_ENDPOINT=""

View File

@@ -103,6 +103,9 @@ WECHAT_REDIRECT_PATH="/"
WECHAT_AUTHORIZE_ENDPOINT="https://open.weixin.qq.com/connect/qrconnect" WECHAT_AUTHORIZE_ENDPOINT="https://open.weixin.qq.com/connect/qrconnect"
WECHAT_ACCESS_TOKEN_ENDPOINT="https://api.weixin.qq.com/sns/oauth2/access_token" WECHAT_ACCESS_TOKEN_ENDPOINT="https://api.weixin.qq.com/sns/oauth2/access_token"
WECHAT_USER_INFO_ENDPOINT="https://api.weixin.qq.com/sns/userinfo" WECHAT_USER_INFO_ENDPOINT="https://api.weixin.qq.com/sns/userinfo"
WECHAT_JS_CODE_SESSION_ENDPOINT="https://api.weixin.qq.com/sns/jscode2session"
WECHAT_STABLE_ACCESS_TOKEN_ENDPOINT="https://api.weixin.qq.com/cgi-bin/stable_token"
WECHAT_PHONE_NUMBER_ENDPOINT="https://api.weixin.qq.com/wxa/business/getuserphonenumber"
WECHAT_STATE_TTL_MINUTES="15" WECHAT_STATE_TTL_MINUTES="15"
WECHAT_MOCK_USER_ID="wx-mock-user" WECHAT_MOCK_USER_ID="wx-mock-user"
WECHAT_MOCK_UNION_ID="wx-mock-union" WECHAT_MOCK_UNION_ID="wx-mock-union"

View File

@@ -1,44 +0,0 @@
name: CI
on:
pull_request:
push:
branches:
- main
- master
jobs:
verify:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.19.0
cache: npm
- name: Install dependencies
run: npm ci
- name: Check encoding
run: npm run check:encoding
- name: Lint
run: npm run lint:eslint
- name: Typecheck
run: npm run typecheck
- name: Test
run: npm run test
- name: Build
run: npm run build
- name: Validate content
run: npm run check:content

5
.gitignore vendored
View File

@@ -35,3 +35,8 @@ temp*build*/
# Local load-test data extracted from private migration files # Local load-test data extracted from private migration files
scripts/loadtest/data/*.local.json scripts/loadtest/data/*.local.json
# Local load-test run artifacts
scripts/loadtest/data/k6-*.log
scripts/loadtest/data/k6-*summary*.md
scripts/loadtest/data/latest-*-prefix.txt

View File

@@ -0,0 +1,206 @@
# 远端作品列表压测排查报告
时间2026-05-12 06:16 CST
目标:`http://82.157.175.59`
SSH远端生产机 root 账号(具体私钥路径仅保留在本机环境,不写入仓库)
## 背景
远端 `k6-works-list.js` 压测中:
- smoke 通过。
- baseline 10 VU无 HTTP 错误,但 p95/p99 超阈值。
- 50 RPS spike`http_req_failed` / `works_list_shape_error_rate` 约 21.99%。
- 100 RPS spike`http_req_failed` / `works_list_shape_error_rate` 约 25.47%。
- 从 k6 check 看,失败主要集中在 `puzzle_gallery_list``custom_world_gallery_list` 基本正常。
## 已完成排查
### 1. 服务器进程与资源
远端服务监听:
- Rust api-server`127.0.0.1:8082`systemd 服务 `genarrative-api.service`
- SpacetimeDB`127.0.0.1:3101`systemd 服务 `spacetimedb.service`
- Nginx公网 80 反代 `/api/*``127.0.0.1:8082`
服务器规格/状态:
- 2 vCPU。
- 内存约 1.9GiB。
- Swap 约 1.9GiB,已有约 600MiB 使用。
- `/` 磁盘约 69%。
- Rust api-server 当前 CPU 不高。
- SpacetimeDB 当前 CPU 不高。
发现一个独立异常:
- PM2 下旧 `server-node` 进程 `genarrative` 正在重启风暴。
- cwd`/work/Genarrative/server-node`
- 错误:连接 `127.0.0.1:5432` PostgreSQL 被拒绝。
- PM2 restart 次数已超过 33 万。
- 该进程不是当前公网 `/api/*` 使用的 Rust api-server但会制造额外 CPU/内存/日志抖动。
### 2. 压测窗口服务端日志
子任务聚合了 2026-05-12 04:50-05:05 的 nginx 与 api-server 日志。
nginx access
- `/api/runtime/puzzle/gallery`4661 次,全部 200。
- `/api/runtime/custom-world-gallery`4659 次,全部 200。
api-server journal
`/api/runtime/puzzle/gallery`
- completed4661
- status200 全部
- slow_request0
- latency_msmin 13 / p50 30 / p90 43 / p95 50 / p99 62 / max 88
`/api/runtime/custom-world-gallery`
- completed4659
- status200 全部
- slow_request0
- latency_msmin 0 / p50 1 / p90 5 / p95 7 / p99 13 / max 49
结论:
- 在服务端视角,两个接口在该窗口都没有 5xx也没有慢请求。
- 这与 k6 客户端侧 30s timeout / failed check 存在明显不一致。
- 需要进一步区分:客户端侧网络/连接耗尽/本机 k6 执行环境问题,还是 k6 统计混合/响应解析问题。
### 3. k6 脚本行为
文件:`scripts/loadtest/k6-works-list.js`
`AUTH_TOKEN` 时,每轮 iteration 顺序请求两个接口:
1. `GET /api/runtime/puzzle/gallery`
2. `GET /api/runtime/custom-world-gallery`
`DETAIL_RATIO=0` 时不会请求详情。
`works_list_shape_error_rate` 不只代表字段结构错误,只要下面任意 check 失败都会计入:
- status is 200
- returns json object
- has collection
- list item shape
因此 timeout、非 JSON、非 200、响应结构不符合都会表现为 shape error。
数据文件实际路径:
- `scripts/loadtest/data/works-list.local.json`
脚本里 `data/works-list.local.json` 是相对 k6 脚本文件解析的,因此本身合理。
### 4. 代码层疑似瓶颈
虽然这次远端服务端日志没有复现慢请求,但代码层仍发现一个真实性能隐患。
`/api/runtime/puzzle/gallery` 调用链:
- `server-rs/crates/api-server/src/app.rs:1192`
- `server-rs/crates/api-server/src/puzzle.rs:1385-1409`
- `server-rs/crates/spacetime-client/src/puzzle.rs:367-381`
- `server-rs/crates/spacetime-module/src/puzzle.rs:430-443`
- `server-rs/crates/spacetime-module/src/puzzle.rs:1393-1404`
关键实现:
- `list_puzzle_gallery_tx``puzzle_work_profile().iter()` 全表扫描。
- 再过滤 `publication_status == Published`
- 对每个公开作品调用 `build_puzzle_work_profile_from_row_with_recent_count`
- 该函数调用 `count_recent_public_work_plays(ctx, "puzzle", &row.profile_id, now_micros)`
`count_recent_public_work_plays`
- 文件:`server-rs/crates/spacetime-module/src/runtime/profile.rs:1296-1321`
- 当前实现对 `public_work_play_daily_stat().iter()` 全表扫描过滤。
- 但表定义已有复合索引:
- `server-rs/crates/spacetime-module/src/runtime/profile.rs:242-248`
- `by_public_work_play_daily_stat_work_day(source_type, profile_id, played_day)`
- 当前统计函数未使用该索引。
复杂度风险:
```text
puzzle gallery ~= O(puzzle_work_profile 全表扫描 + Published作品数 * public_work_play_daily_stat 全表扫描)
```
`custom-world-gallery` 与 puzzle 的差异:
- custom-world 使用 `CustomWorldGalleryEntry` 公开读模型表。
- puzzle 直接从 `puzzle_work_profile` 即席拼装。
- 两者都调用 recent count但 puzzle 更容易受作品表规模和统计表规模影响。
## 当前判断
本次排查有两个层面的结论:
1. 生产服务端日志没有证明 `puzzle/gallery` 在 04:50-05:05 窗口真的 30s 慢或 5xx。
- api-server 记录的 p95 只有 50ms。
- nginx 看到两个接口都是 200。
- 所以 k6 侧的 30s timeout 需要进一步从客户端网络、连接池、Windows/k6 执行环境、summary 混合统计角度验证。
2. 代码层确实存在可修的性能隐患。
- `count_recent_public_work_plays` 未使用已有索引。
- puzzle gallery 对每个作品重复做 recent count。
- puzzle gallery 未使用 `publication_status` 索引或读模型。
## 建议下一步
### A. 先处理服务器 PM2 重启风暴
建议确认旧 Node 服务是否仍需要。
如果不需要,应停止并禁用 PM2 中的旧 `server-node`
```bash
PM2_HOME=/home/ubuntu/.pm2 pm2 stop genarrative
PM2_HOME=/home/ubuntu/.pm2 pm2 delete genarrative
PM2_HOME=/home/ubuntu/.pm2 pm2 save
```
这是生产侧操作,执行前需要确认。
### B. 单接口短压验证客户端/服务端不一致
不要继续用混合脚本大压。
建议新增或临时使用单接口 k6 脚本,分别只测:
- `/api/runtime/puzzle/gallery`
- `/api/runtime/custom-world-gallery`
并在同一时间窗口并行采集:
- k6 客户端 summary
- nginx access 请求数/状态码
- api-server journal latency
- 本机到服务器网络错误/timeout
目标是确认 timeout 是不是发生在客户端侧连接/网络,而不是服务端处理慢。
### C. 修复代码性能隐患
优先级建议:
1. `count_recent_public_work_plays` 改为使用 `by_public_work_play_daily_stat_work_day` 复合索引,或至少改成批量统计,避免 N 次全表扫描。
2. `list_puzzle_gallery_tx` 使用 `by_puzzle_work_publication_status` 索引查询 Published或参考 custom-world 建立 `puzzle_gallery_entry` 公开读模型。
3. gallery 列表页不要实时逐条扫描统计表,可维护读模型或批量聚合 `recent_play_count_7d`
### D. 调整 k6 脚本输出
建议 k6 summary 按 endpoint tag 输出或新增单接口模式,否则 overall 指标会把 puzzle/custom-world 混在一起。
建议增加:
- `ENDPOINT=puzzle_gallery_list`
- `ENDPOINT=custom_world_gallery_list`
让脚本只跑一个 endpoint避免诊断时混淆。

View File

@@ -0,0 +1,343 @@
# Genarrative 视觉小说“一句话生成”最小闭环落地计划
生成时间2026-05-13 11:22
工作区:`C:/proj/Genarrative/.worktrees/hermes-visual-novel`
参考文档:`C:/Users/DSK/Documents/Interactive-fiction/一句话生成视觉小说整体流程总结.md`
## 1. 目标
把 Interactive-fiction 总结文档中的“一句话生成视觉小说”流程,映射并落地到 Genarrative 现有视觉小说能力中,优先做成一个可端到端验证的最小闭环:
1. 用户在视觉小说入口输入一句话并选择画风。
2. 前端进入生成过程页,展示分阶段进度。
3. 后端创建视觉小说创作会话,并基于 seedText 生成 `VisualNovelResultDraft`
4. 生成完成后进入草稿结果页,可看到世界观、角色、场景、剧情阶段、开场选择。
5. 草稿可编译/保存为作品 profile并进入视觉小说运行态测试/正式游玩。
本计划只覆盖 Genarrative 内部最小闭环,不引入 Interactive-fiction 原项目的独立 TXT 播放记录、分享播放包、外部活动运营、独立账号/交易/资产系统。
## 2. 当前上下文与已发现实现
### 2.1 Interactive-fiction 总结文档提炼
参考文档将整体流程分为:
- 输入侧:一句话创意、主题/风格、可选文档或素材。
- 生成侧:理解意图、扩展世界观、角色、场景、剧情阶段、开场与选择。
- 编辑侧:草稿页可查看和调整生成结果。
- 运行侧:从草稿进入视觉小说游玩,支持剧情推进、玩家选择、历史与状态。
- 资产侧:角色立绘、背景、音乐/音效可作为后续增强,最小闭环可先使用文字描述与空资产占位。
### 2.2 Genarrative 已有实现基础
已确认项目中视觉小说相关能力并非从零开始:
- 前端入口表单:
- `src/components/visual-novel-creation/VisualNovelAgentWorkspace.tsx`
- 已有“一句话创作” textarea、6 个视觉画风选项、提交按钮“生成视觉小说草稿”。
- 前端入口 payload/progress
- `src/components/visual-novel-creation/visualNovelEntryGeneration.ts`
- 已有 `VisualNovelEntryFormPayload`、锚点展示、一句话/画风生成进度步骤。
- 前端平台主流程:
- `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
- 已接入 `createVisualNovelDraftFromForm`,会创建 session、stream message、进入 `visual-novel-generating`,完成后进入 `visual-novel-result`
- 前端 API client
- `src/services/visual-novel-creation/visualNovelCreationClient.ts`
- 已封装 session/message/action/compile 接口。
- 共享契约:
- `packages/shared/src/contracts/visualNovel.ts`
- 已定义 `VisualNovelResultDraft`、world/characters/scenes/storyPhases/opening/runtimeConfig/work/run/history 等结构。
- 后端 API
- `server-rs/crates/api-server/src/visual_novel.rs`
- 已有创建 session、发消息、流式消息、执行 action、compile、work、runtime run 等接口。
- 后端 prompt
- `server-rs/crates/api-server/src/prompt/visual_novel.rs`
- 已有 `VISUAL_NOVEL_CREATION_SYSTEM_PROMPT`、结构化输出契约、runtime GM prompt、repair prompt。
- SpacetimeDB 模块:
- `server-rs/crates/spacetime-module/src/visual_novel.rs`
- 已有 session/message/work/run/history/event 表与 procedure。
- 文档参考:
- `docs/prd/AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.md`
- `docs/technical/VISUAL_NOVEL_IMPLEMENTATION_HANDOFF_2026-05-07.md`
- `docs/technical/VISUAL_NOVEL_PROMPT_AND_LLM_TOOLS_VN03_2026-05-05.md`
### 2.3 关键实现判断
当前项目已经实现了视觉小说的主要骨架,本次不应大规模重写。更合理的落地方式是补齐“一句话生成”闭环中最容易断裂的点:
- 入口输入与画风信息是否被稳定传给后端 prompt。
- 后端生成 draft 后是否自动保存/关联可编辑 work profile。
- 生成过程页是否能清晰展示 Interactive-fiction 文档中提到的阶段。
- 结果页是否有足够的字段展示与继续游玩入口。
- 运行态是否能基于 opening/choices 正常启动,而不依赖尚未生成的图片/音乐资产。
## 3. 拟采用方案
### 3.1 最小闭环范围
本次优先实现:
1. “一句话 + 视觉画风”作为 `sourceMode: 'idea'` 的 seedText。
2. 后端生成完整 `VisualNovelResultDraft`,包括:
- world
- 3-6 个角色
- 3-8 个场景
- 3-6 个剧情阶段
- opening narration/firstDialogue/2-4 个 choices
- runtimeConfig
3. 若 LLM 输出失败,使用 repair 或确定性 fallback保证可回到草稿页并显示错误/警告。
4. 结果页支持保存/编译为 work profile。
5. work profile 支持启动 runtime runopening 能展示初始场景、旁白、对话和选择。
暂不做或仅预留:
- 真实图片/音乐生成队列。
- 多文档解析导入的完整链路。
- 复杂分镜/节点图编辑器。
- 外部 Interactive-fiction 项目的播放器、TXT 记录包、分享活动、独立账号系统。
### 3.2 与 Genarrative 架构的映射
| Interactive-fiction 概念 | Genarrative 落点 |
| --- | --- |
| 一句话创意 | `VisualNovelEntryFormPayload.ideaText` / `seedText` |
| 画风/主题 | `seedText` 中的“视觉画风/画风要求”,后续可结构化为 metadata |
| 世界观设定 | `VisualNovelResultDraft.world` |
| 角色设定 | `VisualNovelResultDraft.characters` |
| 场景设定 | `VisualNovelResultDraft.scenes` |
| 剧情阶段/章节 | `VisualNovelResultDraft.storyPhases` |
| 开场文本与选项 | `VisualNovelResultDraft.opening` |
| 运行时剧情推进 | `VisualNovelRuntimeStep[]` + run snapshot/history |
| 发布/作品库 | `VisualNovelWorkProfileRecord` / works API |
## 4. 分步计划
### Step 1补齐入口 payload 与生成过程语义
涉及文件:
- `src/components/visual-novel-creation/VisualNovelAgentWorkspace.tsx`
- `src/components/visual-novel-creation/visualNovelEntryGeneration.ts`
- `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
任务:
1. 保持现有 6 个画风选项,但确认每个 option 的 prompt 会进入 `seedText`
2. 将生成过程阶段从当前 3 步细化为更贴合参考文档的 4-5 步,例如:
- 理解一句话创意
- 扩展世界观与玩家身份
- 设计角色/场景/剧情阶段
- 生成开场与选择
- 准备可编辑草稿
3. 生成过程页的 anchor 保留“一句话”和“视觉画风”,必要时增加“生成目标:视觉小说草稿”。
4. 确认 `createVisualNovelDraftFromForm` 对失败状态会保留返回入口/重试能力。
验收点:提交一句话后能进入 `visual-novel-generating`,看到阶段进度;完成后进入 `visual-novel-result`
### Step 2增强后端 creation prompt 与 fallback 约束
涉及文件:
- `server-rs/crates/api-server/src/prompt/visual_novel.rs`
- `server-rs/crates/api-server/src/visual_novel.rs`
- 如已有 domain crate`server-rs/crates/module-visual-novel/**` 或相关 normalize/validate 文件
任务:
1. 在 creation prompt 中显式吸收 Interactive-fiction 的“一句话生成”目标:
- 从 seedText 提取核心创意、视觉风格、故事类型。
- 生成可直接运行的 opening 和 choices。
- 图片/音乐资产先置 null但必须有可生成图像的描述。
2. 强化输出约束:
- `opening.sceneId` 必须指向存在且 availability 为 `opening` 的 scene。
- `opening.initialChoices` 必须 2-4 个。
- `storyPhases[0]` 必须包含 opening scene 和主要角色。
- `publishReady` 的判定与 validationIssues 一致。
3. 检查 `submit_visual_novel_message_turn` / `resolve_action_draft` / compile 相关代码:
- 如果 LLM 失败,是否已有 fallback没有则补确定性 fallback draft。
- 如果 draft 不完整,是否会 normalize/repair 并写入 session。
4. 保留现有“不要输出旧 TXT 播放记录、分享播放包、外部商业字段”的约束,避免把参考项目的外部概念误并入 Genarrative。
验收点:后端给定 seedText 时,返回 session.draft 不为空且满足共享契约。
### Step 3确认草稿结果页、保存/编译与作品库链路
涉及文件:
- `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
- `src/components/visual-novel-creation/**`
- `src/services/visual-novel-works*` 或相关 visual novel works client
- `server-rs/crates/api-server/src/visual_novel.rs`
- `packages/shared/src/contracts/visualNovel.ts`
任务:
1. 查找并确认 `visual-novel-result` 页面组件:
- 是否显示 workTitle/workDescription/world/characters/scenes/storyPhases/opening。
- 是否有保存/发布/开始试玩按钮。
2. 确认 `compileVisualNovelWorkProfile``executeVisualNovelAction({kind:'compile_work_profile'})` 会生成/更新 work profile。
3. 确认作品架上使用 `profileId` 而不是 sessionId 作为稳定作品 ID。
4. 如果结果页缺少“一句话来源/画风”的可视化提示,可在结果页或 summary 中补轻量展示,避免用户以为画风丢失。
验收点:生成完成后能保存为作品;作品出现在“我的作品/创作架”;再次打开能读取同一 draft。
### Step 4确认运行态 opening 闭环
涉及文件:
- `src/components/visual-novel-runtime/**`
- `src/services/visual-novel-runtime*`
- `server-rs/crates/api-server/src/visual_novel.rs`
- `server-rs/crates/api-server/src/prompt/visual_novel.rs`
- `packages/shared/src/contracts/visualNovel.ts`
任务:
1. 启动 visual novel work run 时,优先使用 `draft.opening` 生成第一轮 runtime snapshot/history。
2. 如果没有图片/音乐,前端 runtime shell 必须可用文字 fallback不应白屏或阻断游玩。
3. 玩家选择 `choice` 后,后端 runtime GM prompt 生成下一轮 `VisualNovelRuntimeStep[]`
4. 确认正式游玩入口调用 `work_play_start`,并满足已有埋点约定:
- `scope_kind=work`
- `scope_id=稳定作品 ID`
- metadata 包含 `playType/workId/sourceRoute/userId` 等。
验收点:从生成出的作品进入运行态,能看到 opening 并点击至少一个选择推进一轮。
### Step 5补测试与文档
涉及文件:
- 前端测试:按仓库现有测试布局查找 `*.test.ts` / `*.test.tsx`
- Rust 测试:`server-rs/crates/api-server/src/**` 或 domain crate tests
- 文档:可追加到 `docs/technical/``.hermes/shared-memory/decision-log.md`(如团队约定需要)
建议测试:
1. TypeScript 单元测试:
- `buildVisualNovelEntryGenerationProgress` 阶段输出。
- `buildVisualNovelEntryGenerationAnchorEntries` 能展示一句话和画风。
2. Rust 单元测试:
- creation prompt 包含 seedText、sourceMode、输出契约。
- draft normalize/fallback 能生成合法 opening/choices。
- runtime opening 或 first-step 构造不依赖图片/音乐。
3. 集成/手工测试文档:
- 访问平台视觉小说入口。
- 输入一句话。
- 选择画风。
- 点击生成。
- 查看结果页。
- 保存作品。
- 启动试玩并点击选择。
## 5. 可能改动文件清单
高概率改动:
- `src/components/visual-novel-creation/VisualNovelAgentWorkspace.tsx`
- `src/components/visual-novel-creation/visualNovelEntryGeneration.ts`
- `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
- `server-rs/crates/api-server/src/prompt/visual_novel.rs`
- `server-rs/crates/api-server/src/visual_novel.rs`
- `packages/shared/src/contracts/visualNovel.ts`
中概率改动:
- `src/components/visual-novel-runtime/**`
- `src/services/visual-novel-creation/**`
- `src/services/visual-novel-runtime/**`
- `src/services/visual-novel-works/**`
- `server-rs/crates/spacetime-module/src/visual_novel.rs`
- `server-rs/crates/spacetime-client/**` 生成/绑定文件,若 SpacetimeDB contract 需要更新
低概率/仅文档:
- `docs/technical/VISUAL_NOVEL_IMPLEMENTATION_HANDOFF_2026-05-07.md`
- `docs/prd/AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.md`
- `.hermes/shared-memory/decision-log.md`
## 6. 验证计划
### 6.1 静态检查
在 worktree 根目录执行:
```bash
npm run typecheck
```
如仓库无统一 typecheck则按 package scripts 选择最接近的前端类型检查命令。
### 6.2 前端定向测试
优先运行与 visual novel / platform entry 相关测试,如存在:
```bash
npm test -- visual-novel
npm test -- platform-entry
```
若仓库使用 vitest
```bash
npm run test -- visual-novel
```
### 6.3 Rust 定向测试
`server-rs` 下运行 visual novel 相关测试:
```bash
cargo test -p api-server visual_novel
cargo test -p shared-contracts visual_novel
```
如改动 SpacetimeDB module
```bash
cargo test -p spacetime-module visual_novel
```
### 6.4 人工验收步骤
1. 启动本地 dev 栈。
2. 访问 Genarrative 主站。
3. 进入创作/视觉小说入口。
4. 输入:`一个雨夜,失忆的高中生在旧图书馆发现一本会回应她心声的日记。`
5. 选择任一画风,例如“映画动画”。
6. 点击“生成视觉小说草稿”。
7. 预期:进入生成过程页,能看到分阶段进度。
8. 预期:完成后进入草稿结果页,包含标题、简介、世界观、角色、场景、剧情阶段和 opening choices。
9. 点击保存/编译作品。
10. 从作品入口进入试玩。
11. 预期opening 文本出现,至少 2 个选择可点击;点击后剧情继续推进一轮。
## 7. 风险、权衡与开放问题
### 7.1 风险
- 现有视觉小说代码已较完整,贸然新增一套 parallel pipeline 会制造重复逻辑;应复用当前 `VisualNovelResultDraft` 与 creation agent flow。
- LLM 输出不稳定可能导致草稿结构不完整;需要 normalize/repair/fallback 确保最小闭环。
- 视觉/音乐资产生成未接入时UI 必须接受 null asset否则运行态可能白屏。
- `PlatformEntryFlowShellImpl.tsx` 文件很大,改动需局部、谨慎,避免影响其他玩法入口。
- 若改动 SpacetimeDB 表结构,可能牵涉 publish、client binding、清库/迁移;最小闭环阶段应尽量避免 schema 变更。
### 7.2 权衡
- 先让文字版视觉小说完整跑通,再补角色立绘/背景图生成。
- 先用 `seedText` 承载画风,再考虑把 `visualStyleId/Label/Prompt` 结构化进 draft metadata。
- 先用现有 result/work/runtime 页面闭环,不引入新编辑器。
### 7.3 开放问题
1. 用户是否要求把 Interactive-fiction 原项目中的具体 UI 样式/页面布局迁移到 Genarrative当前计划只迁移流程语义不迁移独立 UI。
2. 画风是否需要成为作品可编辑字段?当前以 seedText/prompt 影响生成内容,后续可在 draft 中增加 metadata。
3. 文档导入模式是否本期要做当前计划聚焦一句话模式document 模式只保留契约能力。
4. 是否需要真实图片/音乐生成?当前计划作为后续增强,不纳入最小闭环。
## 8. 建议实施顺序
1. 先做只改 prompt/progress/少量前端展示的轻量闭环修补。
2. 运行前后端定向测试,确认现有能力是否已足够。
3. 如果后端没有 fallback 或 normalize再补 Rust 层确定性兜底。
4. 手工跑通“一句话 -> 生成 -> 结果页 -> 保存 -> 试玩”。
5. 最后再考虑是否需要资产生成、文档导入、结构化画风 metadata。

View File

@@ -16,20 +16,132 @@
--- ---
## 2026-05-14 抓大鹅物品素材 sheet 改用 APIMart nanobanana
- 背景:抓大鹅 2D 五视角物品素材仍沿用 5x5 sheet、绿幕去背、切图、OSS 转存和 `generatedItemAssets` 持久化,但用户要求物品素材图片生成步骤改用 APIMart 已接好的 nanobanana / Gemini 图片模型。
- 决策:抓大鹅物品素材 sheet 生图固定走 APIMart `POST {APIMART_BASE_URL}/images/generations`,模型为 `gemini-3.1-flash-image-preview``size = 1:1``resolution = 1K``official_fallback = true`;响应优先读图片 URL 或 base64缺图片时按 `task_id` 轮询 `/tasks/{task_id}`。封面、9:16 纯背景图、1:1 容器 UI 图、音频、切图、OSS、扣费和运行态消费链路保持不变。
- 影响范围:`server-rs/crates/api-server/src/match3d.rs``server-rs/crates/api-server/src/config.rs``deploy/env/api-server.env.example`、抓大鹅素材生成技术文档。
- 验证方式:执行 `cargo test -p api-server match3d_material_sheet --manifest-path server-rs\Cargo.toml``cargo test -p api-server from_env_reads_non_public_models_and_urls --manifest-path server-rs\Cargo.toml``cargo check -p api-server --manifest-path server-rs\Cargo.toml``npm run check:encoding`
- 关联文档:`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 2026-05-13 认证运行期同步直接导入正式认证表
- 背景:`auth_store_snapshot` 是 Stage 1 整包快照过渡表,主键固定 `default`,会让所有用户状态集中在一条 `snapshot_json`Stage 2/3 已有 `user_account/auth_identity/refresh_session` 正式认证表,继续刷新 `default` 容易让运行时真相和表拆分目标混在一起。
- 决策:运行期认证变更继续由 `module-auth` 生成一致内存快照,但 `api-server` 改为调用 `import_auth_store_snapshot_json` 直接覆盖导入 `user_account/auth_identity/refresh_session``auth_store_projection_meta/default` 只记录正式认证表最近一次导入时间;`upsert_auth_store_snapshot``import_auth_store_snapshot` 仅保留为旧库迁移和兜底入口。
- 影响范围:`spacetime-module` auth procedures/tables、`spacetime-client` auth facade/bindings、`api-server` 认证同步和启动恢复、SpacetimeDB 表目录与认证 Stage 3 文档。
- 验证方式:执行 `npm run spacetime:generate -- --rust-only``cargo check -p api-server --manifest-path server-rs/Cargo.toml`、认证相关定向测试和 `npm run check:encoding`
- 关联文档:`docs/technical/AUTH_SPACETIMEDB_FORMAL_TABLE_RECOVERY_STAGE3_2026-04-24.md``docs/technical/SPACETIMEDB_TABLE_CATALOG.md`
## 2026-05-13 微信小程序支付以后端通知为唯一入账事实
- 背景:“我的”账户充值需要接入微信小程序支付,同时保留本地 / H5 mock 支付联调能力。
- 决策:`paymentChannel = "mock"` 继续创建即 paid 订单并立即入账;`paymentChannel = "wechat_mp"` 先在 `profile_recharge_order` 写入 `pending` 订单,再由 `api-server` 调微信支付 JSAPI 下单并返回小程序 `wx.requestPayment` 参数。小程序或 H5 的支付成功回调只触发刷新,不直接发放泥点或会员;最终入账只由 `/api/profile/recharge/wechat/notify` 验签、解密并确认 `trade_state = SUCCESS` 后完成。`provider_transaction_id` 保存微信支付平台交易号,用于对账、查单、退款和客服排障。
- 影响范围:`profile_recharge_order` 表、SpacetimeDB 充值 procedure、`api-server` 微信支付客户端、小程序 native 支付页、H5 充值弹窗与共享 contract。
- 验证方式:执行 `npm run typecheck``npm run test -- src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx``cargo test -p module-runtime recharge --manifest-path server-rs/Cargo.toml``cargo test -p api-server wechat_pay --manifest-path server-rs/Cargo.toml`,后端联调仍用 `npm run api-server``/healthz`
- 关联文档:`docs/technical/MY_TAB_ACCOUNT_RECHARGE_IMPLEMENTATION_2026-04-25.md``docs/technical/SPACETIMEDB_TABLE_CATALOG.md`
## 2026-05-13 修改密码后全设备强制下线
- 背景:修改密码原本只递增 `token_version`,旧 access token 会失效,但旧 refresh cookie 仍可通过 `/api/auth/refresh` 重新签发新 token不符合“改密后全设备强制下线”的账号安全预期。
- 决策:`POST /api/auth/password/change` 成功后必须在同一认证真相更新中撤销该用户全部 active `refresh_session`,继续递增 `token_version`,响应清除当前 refresh cookie前端 `changePassword` 成功后清空本地 access token 并回到未登录态。用户需要使用新密码重新登录。
- 影响范围:`module-auth` 修改密码用例、`api-server` password management route、`AuthGate``authService`、密码登录/重置技术文档。
- 验证方式:执行 `cargo test -p api-server --manifest-path server-rs/Cargo.toml password_change_allows_login_with_new_password_only -- --nocapture``npm run test -- AuthGate.test.tsx authService.test.ts``npm run check:encoding``git diff --check`
- 关联文档:`docs/technical/PASSWORD_LOGIN_CHANGE_RESET_DESIGN_2026-04-24.md``docs/technical/AUTH_SESSIONS_QUERY_DESIGN_2026-04-21.md`
## 2026-05-13 refresh_session 会话组后端聚合与远端踢下线
- 背景:账号安全页中同设备同 IP 的多条 active `refresh_session` 会重复展示;退出登录没有稳定撤销当前 refresh session前端“踢下线”只做本地状态变化未真正让远端设备失效。
- 决策:`GET /api/auth/sessions` 由后端按“同设备 + 同 IP”聚合 active refresh sessions响应保留代表 `sessionId` 并新增 `sessionIds/sessionCount`;组内包含当前 refresh hash 或 Bearer `sid` 时整组视为当前设备组,前端不展示踢下线。新增 `POST /api/auth/sessions/{session_id}/revoke`,只允许撤销当前用户自己的非当前会话,不递增 `token_version`,但认证中间件会校验 access token `sid` 对应 active refresh session使被踢设备立即失效。`/api/auth/logout` 在 refresh cookie 缺失时回退用 Bearer `sid` 撤销当前 session并继续递增 `token_version`
- 影响范围:`module-auth` refresh session service、`api-server` auth middleware/logout/sessions route、`shared-contracts`/TS auth contract、`AuthGate``AccountModal`、认证会话技术文档和路由/埋点索引。
- 验证方式:执行 `cargo test -p module-auth --manifest-path server-rs/Cargo.toml refresh_session``cargo test -p api-server --manifest-path server-rs/Cargo.toml auth_sessions -- --nocapture``cargo test -p api-server --manifest-path server-rs/Cargo.toml revoke_auth_session -- --nocapture``cargo test -p api-server --manifest-path server-rs/Cargo.toml logout_succeeds_without_refresh_cookie_when_bearer_token_is_valid -- --nocapture``npm run test -- AuthGate.test.tsx AccountModal.test.tsx authService.test.ts``npm run check:encoding``git diff --check`,并用 `npm run api-server` 检查 `/healthz`
- 关联文档:`docs/technical/AUTH_SESSIONS_QUERY_DESIGN_2026-04-21.md``docs/technical/SPACETIMEDB_REFRESH_SESSION_TABLE_DESIGN_2026-04-21.md``docs/technical/SERVER_RS_DDD_G1_CONTRACT_AND_ROUTE_MATRIX_2026-04-29.md`
## 2026-05-12 抓大鹅入口素材风格改为 2D 常见素材风格
- 背景:抓大鹅草稿素材生成已经收敛为多视角 2D 图片素材,但入口页和旧参考图仍沿用黏土、低多边形、塑料、木雕、体素、金属等偏 3D 素材语言,容易让后续生成链路和用户预期继续漂移。
- 决策:抓大鹅创作入口 `2D素材风格` 固定为 `扁平图标 / 赛璐璐卡通 / 像素复古 / 手绘水彩 / 贴纸描边 / 厚涂图标 / 自定义`;默认风格为 `flat-icon`。入口参考图统一由 `npm run assets:match3d-style-references -- --live` 调用 VectorEngine `gpt-image-2-all` 生成,输出到 `public/match3d-style-references/`。旧 3D 风格参考图不再保留为入口资产。
- 影响范围:`Match3DAgentWorkspace`、抓大鹅入口交互测试、Match3D PRD、素材生成流水线技术文档、F1 入口文档和 `public/match3d-style-references/` 静态资产。
- 验证方式:执行 `npm run test -- src\components\match3d-creation\Match3DAgentWorkspace.interaction.test.tsx``cargo test -p shared-contracts match3d --manifest-path server-rs\Cargo.toml``npm run typecheck``npm run check:encoding`,并人工抽查 `.tmp/match3d-style-preview.png`
- 关联文档:`docs/prd/AI_NATIVE_MATCH3D_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-30.md``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md``docs/technical/MATCH3D_F1_CREATION_ENTRY_AND_AGENT_UI_2026-04-30.md`
## 2026-05-12 拼图与抓大鹅草稿背景音乐按纯音乐自动生成
- 背景:拼图和抓大鹅需要在草稿生成阶段直接产出可试听、可重生成、可进入运行态循环播放的背景音乐。
- 决策:复用通用 VectorEngine Suno 创作音频链路,不新增 SpacetimeDB 表;拼图音乐保存到首关 `PuzzleDraftLevel.backgroundMusic`,运行态通过 `PuzzleRuntimeLevelSnapshot.backgroundMusic` 下发;抓大鹅音乐保存到首个 `generatedItemAssets[].backgroundMusic`。两者草稿生成都使用 `title` 驱动、`prompt = ""``make_instrumental = true`;自动草稿阶段必须拿到可播放 `audioSrc` 才能返回成功,失败时停留在生成页并允许重试同一 session/profile。结果页内的手动重新生成继续作为已有草稿的补救入口。
- 影响范围:`api-server` 音频生成、拼图草稿编译、抓大鹅草稿编译、Puzzle/Match3D 结果页和运行态音频播放。
- 验证方式:检查草稿 response / work detail 中的 `backgroundMusic.audioSrc`,运行态开局后隐藏 audio 循环播放;执行音频相关后端 check、前端 typecheck 和编码检查。
- 关联文档:`docs/technical/PUZZLE_MATCH3D_RESULT_AUDIO_TAB_2026-05-11.md``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 2026-05-12 拼图 UI 背景图复用 levels_json 持久化
- 背景:拼图草稿结果页需要像抓大鹅一样支持 UI 背景生成,但首版只需要作品级/首关背景,不应为图片生成结果新增 SpacetimeDB 表结构。
- 决策:拼图 UI 背景字段存入首关 `levels_json`,字段为 `uiBackgroundPrompt``uiBackgroundImageSrc``uiBackgroundImageObjectKey``compile_puzzle_draft` 草稿编译阶段在首图完成后自动生成首关 UI 背景,自动草稿阶段必须拿到 `uiBackgroundImageSrc``uiBackgroundImageObjectKey` 才能返回成功;结果页新增 `UI` Tab可编辑提示词并触发 `generate_puzzle_ui_background`,手动生成失败只展示在当前面板。`api-server` 读取 `public/ui-previews/puzzle-image-compact-ui-2026-05-08.png` 作为非拼图 UI 参考图,调用 VectorEngine `gpt-image-2-all` 生成 9:16 背景并要求中央正方形拼图区与外部 UI 背景边界清晰。SpacetimeDB 只保存结果,不做外部 I/O。
- 影响范围:拼图结果页、拼图运行态背景渲染、拼图 agent action、`module-puzzle` / `spacetime-module` / `spacetime-client` 的拼图关卡 JSON 映射、拼图流程技术文档。
- 验证方式:执行 `npm run test -- src/components/puzzle-result/PuzzleResultView.test.tsx``cargo test -p api-server puzzle_ui_background --manifest-path server-rs/Cargo.toml``cargo check -p api-server --manifest-path server-rs/Cargo.toml``npm run typecheck``npm run check:encoding`
- 关联文档:`docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md`
## 2026-05-12 抓大鹅结果页素材编辑统一走作品级资产面板
- 背景:抓大鹅结果页需要支持碰面图上传 / AI 重绘、物品素材独立预览、单项删除和批量新增,且不能把素材编辑继续做成列表内联展开或前端临时状态。
- 决策:结果页 `作品信息` 的碰面图点击打开独立面板,参考图可来自本地上传、物品素材和 UI 素材AI 重绘统一调用 `POST /api/creation/match3d/works/{profileId}/cover-image` 并转存到 `generated-match3d-assets``素材配置 > 物品` 列表项点击打开独立预览面板,不再提供单项重新生成按钮;单项删除和批量新增都写回同一份 `generated_item_assets_json`。批量新增调用 `POST /api/creation/match3d/works/{profileId}/item-assets`,复用草稿生成的 2D 素材图、5x5 切图、OSS 上传和可选点击音效链路,仅作用于新增物品,不新增 SpacetimeDB 表。
- 影响范围Match3D 结果页、Match3D works shared contracts、`api-server` Match3D 作品路由、生成资产历史类型和草稿恢复路径。
- 验证方式:执行 `npm run test -- src/components/match3d-result/Match3DResultView.test.tsx``npm run typecheck``cargo test -p api-server match3d --manifest-path server-rs/Cargo.toml``cargo check -p api-server --manifest-path server-rs/Cargo.toml``npm run check:encoding`
- 关联文档:`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 2026-05-12 平台法律文档入口与登录协议确认
- 背景:生产发布需要在个人页展示用户协议、隐私政策、免责声明和备案号;登录页首次登录需要显式确认法律协议。
- 决策:法律文档内容读取 `media/files/*.md`,统一通过 `LegalDocumentModal` 独立弹窗展示;“我的”页常用功能区固定 3 列,设置入口下方展示法律信息和 `京ICP备2026025677号` 外链。登录弹窗用 `genarrative.auth.legal-consent.v1` 记录本机确认,首次未勾选时短信 / 密码登录按钮禁用,法律链接不自动勾选。
- 影响范围:平台个人页、登录弹窗、法律 Markdown 渲染和前端认证交互测试。
- 验证方式:执行 `npm run test -- src/components/auth/AuthGate.test.tsx src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx`、触碰文件 ESLint、`npm run check:encoding`
- 关联文档:`docs/prd/PROFILE_LEGAL_INFO_AND_AUTH_AGREEMENT_PRD_2026-05-12.md`
## 2026-05-12 微信小程序待绑定手机号优先走原生手机号授权
- 背景:微信小程序 `web-view` 壳登录后若返回 `pending_bind_phone`H5 仍会展示手输手机号和短信验证码绑定页,体验上多了一步。
- 决策:小程序壳在 `pending_bind_phone` 时暂不打开 H5先展示原生 `button open-type="getPhoneNumber"`;用户同意后把 `bindgetphonenumber` 返回的 `code` 作为 `wechatPhoneCode` 调用 `/api/auth/wechat/bind-phone`。后端通过微信 `stable_token``getuserphonenumber` 换取平台验证后的手机号,再复用现有微信待绑定账号合并逻辑并重新签发 active 系统 token。H5 旧短信验证码绑定流程继续作为非小程序环境兜底。
- 影响范围:`miniprogram/pages/web-view/index.*``server-rs/crates/platform-auth``server-rs/crates/api-server/src/wechat_auth.rs`、认证共享契约、微信小程序 web-view 壳技术文档。
- 验证方式:执行 `npm run check:encoding``node scripts/check-wechat-miniprogram-auth-smoke.mjs``cargo test -p shared-contracts wechat_bind_phone_request_accepts_mini_program_phone_code --manifest-path server-rs/Cargo.toml``cargo test -p api-server wechat_miniprogram_bind_phone_code_activates_pending_user --manifest-path server-rs/Cargo.toml -- --nocapture`
- 关联文档:`docs/technical/WECHAT_MINIPROGRAM_WEB_VIEW_SHELL_2026-05-03.md`
## 2026-05-13 宝贝爱画先作为寓教于乐独立本地 Demo 落地
- 背景:第三关 `宝贝爱画` 需要默认出现在“发现 / 寓教于乐”板块下方,但本阶段只验证画板、手部绘制、绘画魔法和本地保存闭环,不进入创作模板、公开作品或正式持久化。
- 决策:`baby-love-drawing / 宝贝爱画` 先作为独立运行态接入,入口由发现页寓教于乐默认卡片打开,并支持 `/runtime/baby-love-drawing` 直达;关闭 `VITE_ENABLE_EDUTAINMENT_ENTRY` 时前端不展示频道/卡片且直达路由回落主应用。绘画魔法统一走 `POST /api/creation/edutainment/baby-love-drawing/magic` 后端安全代理,使用 VectorEngine `gpt-image-2-all` 与原始画布 Data URL 参考图生成绘本风图片;保存只写 localStorage正式持久化后续再设计。
- 影响范围:`packages/shared/src/contracts/edutainmentBabyDrawing.ts``src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.tsx``src/services/edutainment-baby-drawing/``src/routing/appRoutes.tsx``src/components/rpg-entry/RpgEntryHomeView.tsx``server-rs/crates/api-server/src/edutainment_baby_drawing.rs``src/index.css`、宝贝爱画 PRD 与技术方案。
- 验证方式:执行宝贝爱画 model/runtime/service/route 定向测试、`npm run typecheck`、定向 ESLint、`cargo test -p api-server edutainment_baby_drawing --manifest-path server-rs/Cargo.toml``cargo test -p api-server resolves_runtime_paths_to_creation_type_ids --manifest-path server-rs/Cargo.toml` 和编码检查;真实魔法生成需配置 `VECTOR_ENGINE_BASE_URL``VECTOR_ENGINE_API_KEY`
- 关联文档:`docs/prd/BABY_LOVE_DRAWING_EDUTAINMENT_LEVEL_PRD_2026-05-13.md``docs/technical/BABY_LOVE_DRAWING_RUNTIME_DEMO_IMPLEMENTATION_2026-05-13.md`
## 2026-05-12 宝贝识物创作同时生成玩法视觉主题包
- 背景:`宝贝识物` 创作原本只根据两个关键词生成物品透明图运行态背景、UI、礼物盒和篮子仍使用固定 CSS 绘本风,无法根据“小猪佩琪 / 奥特曼”或“苹果 / 橘子”等创作者提示词做主题化包装。
- 决策:`POST /api/creation/edutainment/baby-object-match/assets` 同一次 image-2 / VectorEngine 调用链返回两个物品图和 `visualPackage`。视觉包包含 `background``ui-frame``gift-box``basket``smoke-puff` 五类资源;总风格保持寓教于乐明亮卡通绘本插画风,主题按两个物品关键词匹配,水果偏果园自然,动漫角色 / 玩具偏动漫玩具。物品图和礼物盒 / 篮子 / UI / 烟雾特效资源走透明 PNG 后处理,背景为清爽不遮挡玩法区的环境图;运行态中礼物盒按约 2 倍视觉尺寸展示、篮子按约 1.5 倍展示,礼物盒打开时使用 `smoke-puff` 弹出中央物品并移除礼盒。前端草稿保存该包,运行态消费该包;旧草稿以 `visualPackage = null` 继续使用 CSS 兜底。
- 影响范围:`packages/shared/src/contracts/edutainmentBabyObject.ts``server-rs/crates/api-server/src/edutainment_baby_object.rs``src/services/edutainment-baby-object/babyObjectMatchClient.ts``src/components/edutainment-runtime/BabyObjectMatchRuntimeShell.tsx``src/index.css`、宝贝识物 PRD 与技术方案。
- 验证方式:执行宝贝识物 service / runtime 定向测试、`cargo test -p api-server edutainment_baby_object --manifest-path server-rs/Cargo.toml`、相关 ESLint 与编码检查;真实生图需配置 `VECTOR_ENGINE_BASE_URL``VECTOR_ENGINE_API_KEY`
- 关联文档:`docs/prd/BABY_OBJECT_MATCH_EDUTAINMENT_TEMPLATE_PRD_2026-05-11.md``docs/technical/BABY_OBJECT_MATCH_CREATION_PUBLISH_IMPLEMENTATION_2026-05-11.md`
## 2026-05-11 拼图与抓大鹅结果页音频资产复用通用创作音频链路 ## 2026-05-11 拼图与抓大鹅结果页音频资产复用通用创作音频链路
- 背景:拼图和抓大鹅结果页需要接入 Suno 背景音乐,抓大鹅还需要物体点击音效,但当前两类作品没有独立的作品级音频表或 metadata 字段。 - 背景:拼图和抓大鹅结果页需要接入 Suno 背景音乐,抓大鹅还需要物体点击音效,但当前两类作品没有独立的作品级音频表或 metadata 字段。
- 决策:新增 `/api/creation/audio/*` 通用创作音频路由,后端统一负责 VectorEngine 音频任务、OSS 转存、`asset_object``asset_entity_binding` 写入;视觉小说旧路由保留并复用同一持久化逻辑。拼图背景音乐暂存到首关 `levels_json[0].backgroundMusic/background_music`;抓大鹅背景音乐暂存到 `generated_item_assets_json[0].backgroundMusic/background_music`,单物体点击音效存到对应 item 的 `clickSound/click_sound`。本轮不新增 SpacetimeDB 表和字段。 - 决策:新增 `/api/creation/audio/*` 通用创作音频路由,后端统一负责 VectorEngine 音频任务、OSS 转存、`asset_object``asset_entity_binding` 写入;视觉小说旧路由保留并复用同一持久化逻辑。拼图背景音乐暂存到首关 `levels_json[0].backgroundMusic/background_music`;抓大鹅背景音乐暂存到 `generated_item_assets_json[0].backgroundMusic/background_music`,单物体点击音效存到对应 item 的 `clickSound/click_sound`。本轮不新增 SpacetimeDB 表和字段。
- 2026-05-12 补充:抓大鹅入口页新增 `generateClickSound` 开关,默认关闭;开启时 `match3d_compile_draft` 在生成首批 2D 物品素材后并行生成各物品点击音效,并继续复用通用创作音频路由的 OSS、资产绑定和扣费口径。
- 影响范围:拼图结果页、抓大鹅结果页、抓大鹅运行态音频播放、通用创作音频 shared contracts、`api-server` 音频路由和资产绑定。 - 影响范围:拼图结果页、抓大鹅结果页、抓大鹅运行态音频播放、通用创作音频 shared contracts、`api-server` 音频路由和资产绑定。
- 验证方式:执行拼图/抓大鹅结果页定向测试、`npm run typecheck``cargo test -p api-server vector_engine_audio_generation``cargo test -p shared-contracts creation_audio``cargo check -p api-server`,真实生成需配置 VectorEngine 与 OSS 私密环境。 - 验证方式:执行拼图/抓大鹅结果页定向测试、`npm run typecheck``cargo test -p api-server vector_engine_audio_generation``cargo test -p shared-contracts creation_audio``cargo check -p api-server`,真实生成需配置 VectorEngine 与 OSS 私密环境。
- 关联文档:`docs/technical/PUZZLE_MATCH3D_RESULT_AUDIO_TAB_2026-05-11.md` - 关联文档:`docs/technical/PUZZLE_MATCH3D_RESULT_AUDIO_TAB_2026-05-11.md`
## 2026-05-11 寓教于乐公开作品使用独立 `edutainment` 来源接入
- 背景:`宝贝识物` 首关需要通过创作模板发布后进入寓教于乐板块,同时关闭入口时必须从发现页、搜索、详情深链、作品号和历史入口完全不可见;若继续落入 RPG 默认公共作品链路,容易出现误启动、误改造或近似标签误归类。
- 决策:寓教于乐公开作品在前端公共作品模型中使用 `sourceType = edutainment`,当前只承接 `templateId = baby-object-match``templateName = 宝贝识物`;进入“发现 / 寓教于乐”频道仍必须携带精确等于 `寓教于乐` 的公开标签,不因模板名或近似标签自动归类。公开详情、推荐运行态、改造、编辑、点赞和分享链路都必须显式识别 `edutainment`,不得回落到 RPG 默认处理。
- 影响范围:公开作品卡、发现页频道、作品号搜索、公开详情深链、分享、作品架聚合、后续儿童动作 Demo 模板的发布结果展示。
- 验证方式执行第4线程定向单测、前端类型检查、ESLint 与编码检查;关闭 `VITE_ENABLE_EDUTAINMENT_ENTRY` 时确认精确 `寓教于乐` 作品不可通过任何公开入口访问。
- 关联文档:`docs/design/CHILD_MOTION_EDUTAINMENT_DISCOVER_ENTRY_2026-05-09.md``docs/prd/BABY_OBJECT_MATCH_EDUTAINMENT_TEMPLATE_PRD_2026-05-11.md``docs/technical/BABY_OBJECT_MATCH_CREATION_PUBLISH_IMPLEMENTATION_2026-05-11.md`
## 2026-05-10 儿童动作 Demo 视觉资产统一为绘本草地舞台 ## 2026-05-10 儿童动作 Demo 视觉资产统一为绘本草地舞台
- 背景:儿童动作 Demo 需要从暗色科技风切换到更适合儿童互动的卡通绘本草地风格,并且要预留 image-2 真实背景图的固定接入位 - 背景:儿童动作 Demo 需要从暗色科技风切换到更适合儿童互动的卡通绘本草地风格,并且要让背景、地面、UI、地面指示环和用户轮廓使用同一套 image-2 资源口径
- 决策:热身舞台统一采用绘本草地视觉语言真实背景图默认输出到 `public/child-motion-demo/picture-book-grass-stage.webp`生成脚本固定为 `scripts/generate-child-motion-demo-assets.mjs`,并通过 `npm run assets:child-motion-demo` 调用 VectorEngine `gpt-image-2-all`。在缺少 `VECTOR_ENGINE_BASE_URL``VECTOR_ENGINE_API_KEY` 时,只允许 dry-run 和 CSS 兜底,不伪造 live 生图结果。 - 决策:热身舞台及后续儿童动作 Demo 场景、物品、UI 资源统一采用明亮卡通绘本草地视觉语言真实资源默认输出到 `public/child-motion-demo/`。背景沿用 `picture-book-grass-stage.png`;地面、指示环、角色轮廓和 UI 已拆分为 v2 用途专属资源:`picture-book-foreground-grass-v2.png``picture-book-ground-ring-v2.png``picture-book-character-outline-v2.png``picture-book-hud-strip-v2.png``picture-book-calibration-strip-v2.png``picture-book-start-panel-v2.png``picture-book-ui-button-v2.png`生成脚本固定为 `scripts/generate-child-motion-demo-assets.mjs`,并通过 `npm run assets:child-motion-demo` 调用 VectorEngine `gpt-image-2-all`;透明资源使用品红底生成后本地去背,中间源图仅保存在 `tmp/child-motion-demo-assets/`。在缺少 `VECTOR_ENGINE_BASE_URL``VECTOR_ENGINE_API_KEY` 时,只允许 dry-run 和 CSS 兜底,不伪造 live 生图结果。
- 影响范围:`src/index.css``src/components/child-motion-demo/ChildMotionWarmupDemo.tsx` 的舞台视觉层、儿童动作 Demo 技术文档、后续 image-2 资产生成流程。 - 影响范围:`src/index.css``src/components/child-motion-demo/ChildMotionWarmupDemo.tsx` 的舞台视觉层、儿童动作 Demo 技术文档、后续 image-2 资产生成流程。
- 验证方式:检查 `/child-motion-demo` 舞台是否在未生成资产时仍有可用草地绘本兜底;补齐 VectorEngine 私密配置后运行 `npm run assets:child-motion-demo -- --live` 应能写出默认背景文件 - 验证方式:检查 `/child-motion-demo` 舞台是否在未生成资产时仍有可用草地绘本兜底;补齐 VectorEngine 私密配置后运行 `npm run assets:child-motion-demo -- --live` `--live --only <asset-id>` 应能写出对应 PNG并确认页面静态资源返回 `image/png`。若只调整透明去背、裁切或品红边缘,可运行 `npm run assets:child-motion-demo -- --live --postprocess-only --force --only <asset-id>` 复用源图后处理。页面接入时必须按资源原始比例等比使用,不得把方形软纸面板拉伸成 HUD、状态条或底部草坪
- 关联文档:`docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md``docs/technical/VECTOR_ENGINE_GPT_IMAGE_2_GENERATION_2026-05-09.md` - 关联文档:`docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md``docs/technical/VECTOR_ENGINE_GPT_IMAGE_2_GENERATION_2026-05-09.md`
## 2026-05-10 方洞挑战从创作页入口和作品架隐藏 ## 2026-05-10 方洞挑战从创作页入口和作品架隐藏
@@ -122,10 +234,10 @@
- 验证方式:未登录首次访问应展示新手引导;生成后只进入 1 关本地拼图;通关后登录保存应在当前用户拼图作品架出现草稿作品;不应产生 SpacetimeDB schema 变更。 - 验证方式:未登录首次访问应展示新手引导;生成后只进入 1 关本地拼图;通关后登录保存应在当前用户拼图作品架出现草稿作品;不应产生 SpacetimeDB schema 变更。
- 关联文档:`docs/prd/FIRST_LAUNCH_PUZZLE_ONBOARDING_PRD_2026-05-05.md` - 关联文档:`docs/prd/FIRST_LAUNCH_PUZZLE_ONBOARDING_PRD_2026-05-05.md`
## 2026-05-05 text-game 作为百梦幕间文字游戏模板接入 ## 2026-05-05 text-game 作为陶泥儿幕间文字游戏模板接入
- 背景:团队希望参考 MOKU / 幕间类 AI 文游,设计可在百梦内落地的 AI 文字游戏模板,但不能把外部平台社区、支付、榜单、论坛、账号或私有存档迁入 Genarrative。 - 背景:团队希望参考 MOKU / 幕间类 AI 文游,设计可在陶泥儿内落地的 AI 文字游戏模板,但不能把外部平台社区、支付、榜单、论坛、账号或私有存档迁入 Genarrative。
- 决策:新增 `text-game` 作为百梦 AI 原生文字游戏模板口径,展示名可用“幕间”或“幕间文字”;它与 `visual-novel` 分离,重点是 AI GM、自由行动、状态后果、长期记忆、章节目标和轻量剧本模拟器入口、作品、发布、资产、钱包、埋点、存档和广场全部复用百梦平台接口;禁止新增 replay、外部社区、外部支付、外部榜单和私有存档系统。 - 决策:新增 `text-game` 作为陶泥儿 AI 原生文字游戏模板口径,展示名可用“幕间”或“幕间文字”;它与 `visual-novel` 分离,重点是 AI GM、自由行动、状态后果、长期记忆、章节目标和轻量剧本模拟器入口、作品、发布、资产、钱包、埋点、存档和广场全部复用陶泥儿平台接口;禁止新增 replay、外部社区、外部支付、外部榜单和私有存档系统。
- 影响范围:后续 `text-game` shared contracts、`module-text-game`、SpacetimeDB 表、`api-server` 路由、前端入口 / workspace / result / runtime、平台作品架和发现聚合。 - 影响范围:后续 `text-game` shared contracts、`module-text-game`、SpacetimeDB 表、`api-server` 路由、前端入口 / workspace / result / runtime、平台作品架和发现聚合。
- 验证方式:后续落地时确认路由使用 `/api/creation/text-game/*``/api/runtime/text-game/*`;确认正式业务真相在 Rust / SpacetimeDB 后端;确认没有 `replay` 能力和外部平台功能误入;确认 `text-game` 不复用 `visual-novel` step 契约作为运行态真相。 - 验证方式:后续落地时确认路由使用 `/api/creation/text-game/*``/api/runtime/text-game/*`;确认正式业务真相在 Rust / SpacetimeDB 后端;确认没有 `replay` 能力和外部平台功能误入;确认 `text-game` 不复用 `visual-novel` step 契约作为运行态真相。
- 关联文档:`docs/prd/AI_NATIVE_TEXT_GAME_TEMPLATE_MOKU_REFERENCE_PRD_2026-05-05.md` - 关联文档:`docs/prd/AI_NATIVE_TEXT_GAME_TEMPLATE_MOKU_REFERENCE_PRD_2026-05-05.md`
@@ -253,10 +365,18 @@
## 2026-05-10 抓大鹅草稿元信息由 gpt-4o 生成 ## 2026-05-10 抓大鹅草稿元信息由 gpt-4o 生成
- 背景:抓大鹅草稿生成需要基于入口题材设定生成作品名称,结果页作品信息要对齐拼图草稿,不再把封面和作品名称拆成两个模块。 - 背景:抓大鹅草稿生成需要基于入口题材设定生成作品名称,结果页作品信息要对齐拼图草稿,不再把封面和作品名称拆成两个模块。
- 决策:`match3d_compile_draft` 使用 `gpt-4o` 生成 `gameName` 与 3 到 6 个标签;`summary` 默认保持空字符串;标签可由结果页 `作品信息` Tab 手动编辑或再次 AI 生成。草稿生成会产出 3 个物品图片并立即调用 Rodin 生成 GLB图片和模型一起写入 `generated_item_assets_json`,运行态必须优先消费 `generatedItemAssets[].modelSrc` / `modelObjectKey`,默认积木只做兜底。 - 决策:`match3d_compile_draft` 使用 `gpt-4o` 生成 `gameName` 与 3 到 6 个标签;`summary` 默认保持空字符串;标签可由结果页 `作品信息` Tab 手动编辑或再次 AI 生成。草稿生成会按难度产出多视角 2D 物品图片并写入 `generated_item_assets_json`,运行态必须优先消费 `generatedItemAssets[].imageViews[]`,默认积木只做兜底。
- 影响范围:`api-server` Match3D 编译、Match3D works 标签接口、结果页 `作品信息``3D素材` Tab、运行态 `Match3DRuntimeShell` / `Match3DPhysicsBoard`、生成进度和 Match3D 技术文档。 - 影响范围:`api-server` Match3D 编译、Match3D works 标签接口、结果页 `作品信息``素材配置` Tab、运行态 `Match3DRuntimeShell` / `Match3DPhysicsBoard`、生成进度和 Match3D 技术文档。
- 验证方式:执行 `npm run test -- src/components/match3d-result/Match3DResultView.test.tsx``npm run test -- src/services/miniGameDraftGenerationProgress.test.ts``cargo test -p api-server match3d --manifest-path server-rs/Cargo.toml``npm run check:encoding`,并用 `npm run api-server` 检查 `/healthz` - 验证方式:执行 `npm run test -- src/components/match3d-result/Match3DResultView.test.tsx``npm run test -- src/services/miniGameDraftGenerationProgress.test.ts``cargo test -p api-server match3d --manifest-path server-rs/Cargo.toml``npm run check:encoding`,并用 `npm run api-server` 检查 `/healthz`
- 关联文档:`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md``docs/technical/MATCH3D_RODIN_ASSET_TAB_2026-05-10.md` - 关联文档:`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md``docs/technical/MATCH3D_RODIN_ASSET_TAB_2026-05-10.md` 仅作历史参考
## 2026-05-12 抓大鹅物品种类从消除次数中拆出并改为 2D 五视角素材
- 背景:结果页草稿素材已经能生成和预览,但标准 / 硬核难度仍可能按 `clearCount` 误判需要 12 / 20 种素材,且继续生产 GLB 会拉长草稿生成耗时。
- 决策:难度配置统一使用 `物品种类`:轻松 3、标准 9、进阶 15、硬核 21历史硬核 `clearCount=20` 在运行态升为 21 组三消。新草稿和批量新增不再调用 Rodin、不再生成 GLB。每个物品生成 5 个不同 2D 视角,单张 1K 素材图固定按 5x5 切割,最多承载 5 个物品;超过 5 个物品时由 `api-server` 自动分批并行生图。发布必须校验已生成 `image_ready` 且有 `imageViews[]` 或首图引用的素材数量满足当前难度;试玩通过 `itemTypeCountOverride` 自动降到可用 2D 素材数量。历史模型字段只作为旧数据兼容,不再进入新生产链路。
- 影响范围Match3D 结果页、运行态启动契约、`module-match3d` 初始 run 生成、SpacetimeDB start input / restart、发布校验和 Match3D 技术文档。
- 验证方式:`npm run test -- src/components/match3d-result/Match3DResultView.test.tsx``cargo test -p module-match3d --manifest-path server-rs\Cargo.toml`、相关后端 check / tests。
- 关联文档:`docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 2026-05-07 移动端整页缩放由入口统一锁定 ## 2026-05-07 移动端整页缩放由入口统一锁定

View File

@@ -22,6 +22,22 @@
- 验证:运行 `cd server-rs && cargo test -p platform-oss -- --nocapture`,并用 bucket=`xushi-dev`、object_key=`generated-square-hole-assets/square-hole-session-546d881972684be2980a2a882cd0cc71/square-hole-profile-134411276ce1469cbe398f946a25d7f8/square-hole-shape-image/rabbit-option/asset-1777979289912039/image.png` 覆盖签名生成。 - 验证:运行 `cd server-rs && cargo test -p platform-oss -- --nocapture`,并用 bucket=`xushi-dev`、object_key=`generated-square-hole-assets/square-hole-session-546d881972684be2980a2a882cd0cc71/square-hole-profile-134411276ce1469cbe398f946a25d7f8/square-hole-shape-image/rabbit-option/asset-1777979289912039/image.png` 覆盖签名生成。
- 关联:`server-rs/crates/platform-oss/src/lib.rs``server-rs/crates/platform-oss/README.md` - 关联:`server-rs/crates/platform-oss/src/lib.rs``server-rs/crates/platform-oss/README.md`
## generated 音频路径进运行态前要先换签
- 现象:草稿页 audio 控件能播放背景音乐但拼图或抓大鹅运行态开局后背景音乐不响Network 可能出现裸 `/generated-*-assets/...mp3` 私有路径 403。
- 原因:生成音乐转存到 OSS 私有对象后,`audioSrc` 是 generated legacy path浏览器 `<audio>` 不能像公开静态资源一样直接请求裸路径。另一个常见误判是浏览器拒绝自动播放,资源已经进入运行态但开局第一次 `audio.play()` 被拦截。
- 处理:结果页试听控件和运行态隐藏 `<audio>` 设置 `src` 前,都先通过 `useResolvedAssetReadUrl``resolveAssetReadUrl` 换签;签名未就绪时不要回退请求裸 generated 路径。运行态自动播放失败只静默兜底,但玩家首次按下拼图块或点击抓大鹅物品时要重试同一个背景音乐播放函数。拼图读取 `currentLevel.backgroundMusic.audioSrc`,抓大鹅读取 `generatedItemAssets[].backgroundMusic.audioSrc`
- 验证:结果页试听和运行态 `<audio loop>``src` 为签名 URL 或公开 URL拼图/抓大鹅运行态首次局内交互后会再次尝试播放背景音乐;`npm run typecheck` 不报契约字段缺失,后端 run response 带 `backgroundMusic`
- 关联:`src/components/puzzle-runtime/PuzzleRuntimeShell.tsx``src/components/match3d-runtime/Match3DRuntimeShell.tsx``docs/technical/PUZZLE_MATCH3D_RESULT_AUDIO_TAB_2026-05-11.md`
## 抓大鹅背景音乐是作品级字段但暂存在首个物品素材
- 现象:抓大鹅草稿生成日志和 work detail 中已有背景音乐,但结果页 `素材配置 > 背景音乐` 显示“暂无音乐”,点击试玩后局内也不播放生成音乐。
- 原因:当前表结构没有作品级音频字段,背景音乐暂存在 `generatedItemAssets[]`。如果 action response 的 draft assets 缺音乐,前端又优先用它覆盖 work detail或音乐落在非首个素材而结果页只读 `assetDrafts[0].backgroundMusic`,就会丢掉已生成音乐。
- 处理:前端统一使用 `normalizeMatch3DGeneratedItemAssetsForRuntime` / `mergeMatch3DGeneratedItemAssetsForRuntime`:把任意素材上的 `backgroundMusic` 与音乐元信息迁移到首个素材清空其它素材上的作品级音乐字段action draft assets 与 work detail assets 按 `itemId` 合并保留详情里的音乐、UI 背景和点击音效。
- 验证:`npm run test -- src\services\match3dGeneratedModelCache.test.ts src\components\match3d-result\Match3DResultView.test.tsx src\components\match3d-runtime\Match3DRuntimeShell.test.tsx`;平台推荐流定向跑 `RpgEntryFlowShell.agent.interaction.test.tsx` 中的 Match3D runtime assets 用例;`npm run typecheck`
- 关联:`src/services/match3dGeneratedModelCache.ts``src/components/match3d-result/Match3DResultView.tsx``src/components/platform-entry/PlatformEntryFlowShellImpl.tsx``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 中文乱码与编码风险 ## 中文乱码与编码风险
- 现象:中文文案、注释、剧情或文档显示为乱码,或被改写成英文。 - 现象:中文文案、注释、剧情或文档显示为乱码,或被改写成英文。
@@ -35,6 +51,24 @@
- 验证:运行仓库已有编码检查;人工抽查修改文件中的中文内容。 - 验证:运行仓库已有编码检查;人工抽查修改文件中的中文内容。
- 关联:`AGENTS.md``npm run check:encoding` - 关联:`AGENTS.md``npm run check:encoding`
## 忘记密码后仍提示手机号或密码错误先查认证快照同步
- 现象:用户通过“忘记密码”重设密码后,接口返回成功或页面进入登录态,但再次使用新密码登录仍提示“手机号或密码错误”;重启后还可能出现 `Bearer JWT 版本已失效`,日志里的 token version 与本地快照不一致。
- 原因:重置/修改密码会更新 `password_hash``password_login_enabled``token_version`,如果 API 层只更新本地 `InMemoryAuthStore`,没有调用 `sync_auth_store_snapshot_to_spacetime()``api-server` 重启时可能从旧的 SpacetimeDB 表或旧快照恢复账号状态。
- 处理:`POST /api/auth/password/change``POST /api/auth/password/reset` 成功后必须同步认证快照;启动恢复时从 SpacetimeDB 表、SpacetimeDB 快照记录和本地 `GENARRATIVE_AUTH_STORE_PATH` 文件中选择可判断的最新快照,本地文件更新时尝试回写 SpacetimeDB。
- 验证:执行 `cargo test -p module-auth password --manifest-path server-rs/Cargo.toml``cargo test -p api-server password --manifest-path server-rs/Cargo.toml`;手测时重设密码后旧密码应失败,新密码应成功,重启后仍应保持。
- 关联:`server-rs/crates/api-server/src/password_management.rs``server-rs/crates/api-server/src/state.rs``docs/technical/PASSWORD_LOGIN_CHANGE_RESET_DESIGN_2026-04-24.md`
## 抓大鹅生成页只显示服务暂不可用先查 reason 和外部服务配置
- 现象:点击生成抓大鹅草稿后,页面只提示“服务暂不可用”,或者本地 `npm run api-server` 看似启动但生成接口不可用。
- 原因:配置缺失类错误通常在后端 `error.details.reason` 中给出具体缺项,前端如果只读 `details.message` 会吞掉原因;本地只配置 `ALIYUN_OSS_BUCKET` / `ALIYUN_OSS_ENDPOINT` 时,旧逻辑还会在启动期构造空 AccessKey 的 OSS 客户端并失败。抓大鹅新链路仍是 2D 生图切割,不需要也不应回退 Rodin/GLB。
- 处理:前端 API 错误展示读取 `details.message` 后继续读取 `details.reason``api-server` 只有在 OSS 四件套齐全时初始化 OSS 客户端,部分缺失只记 warning 并让具体 generated 上传/换签接口返回 `OSS 未完成环境变量配置`。抓大鹅素材、封面和背景生成在调用 VectorEngine 前先预检 OSS并通过 `details.missingEnv` 列出缺项;真实生成需补齐 `VECTOR_ENGINE_BASE_URL``VECTOR_ENGINE_API_KEY` 和完整 `ALIYUN_OSS_*` 四件套。抓大鹅 `5*5` 素材图提示词还必须要求相邻物体主体至少保留 `1/4` 单格宽度空白间距,避免切割后相邻格内容污染。
- 验证:`npm run test -- src/services/apiClient.test.ts` 覆盖 `details.reason``cargo test -p api-server state --manifest-path server-rs/Cargo.toml` 覆盖半配置 OSS 不阻断启动;`npm run api-server` 后按实际 `GENARRATIVE_API_PORT` 请求 `/healthz`,不要默认打 `3100`
- 关联:`packages/shared/src/http.ts``server-rs/crates/api-server/src/state.rs``docs/technical/API_SERVER_EXTERNAL_SERVICE_ENV_CONFIG_2026-05-07.md``docs/technical/AUTH_SNAPSHOT_AND_MATCH3D_LOCAL_DEV_FIX_2026-05-01.md`
2026-05-14 补充:抓大鹅“物品素材 sheet”已改用 APIMart `gemini-3.1-flash-image-preview`,真实生成还需要 `APIMART_BASE_URL``APIMART_API_KEY``APIMART_IMAGE_REQUEST_TIMEOUT_MS`;封面、背景图和容器 UI 仍继续使用 VectorEngine。排查时先按失败阶段区分缺 APIMart、VectorEngine 还是 OSS不能把物品素材缺 APIMart 误判成 VectorEngine 缺配置。
## `.hermes` 只放共享内容,不放个人 Hermes 配置 ## `.hermes` 只放共享内容,不放个人 Hermes 配置
- 现象:团队成员误把个人 Hermes 配置、会话或密钥复制进仓库。 - 现象:团队成员误把个人 Hermes 配置、会话或密钥复制进仓库。
@@ -51,14 +85,71 @@
- 验证:运行 `npx vitest run src\services\useMocapInput.test.ts src\components\child-motion-demo\ChildMotionWarmupDemo.test.tsx`,并在本地硬件服务启动后进入 `/child-motion-demo` 实测站位、招手、左右手挥动和跳跃阶段。 - 验证:运行 `npx vitest run src\services\useMocapInput.test.ts src\components\child-motion-demo\ChildMotionWarmupDemo.test.tsx`,并在本地硬件服务启动后进入 `/child-motion-demo` 实测站位、招手、左右手挥动和跳跃阶段。
- 关联:`src/services/useMocapInput.ts``src/components/child-motion-demo/ChildMotionWarmupDemo.tsx``docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md` - 关联:`src/services/useMocapInput.ts``src/components/child-motion-demo/ChildMotionWarmupDemo.tsx``docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md`
## 儿童动作 Demo 真实绘本背景图未生成先查 VectorEngine 配置 ## 儿童动作 Demo 左右手阶段误通过先查身体侧映射和手臂展开阈值
- 现象:`/child-motion-demo` 已经呈现绘本草地风格,但 `public/child-motion-demo/picture-book-grass-stage.webp` 不存在Network 里该图返回 404或运行 `npm run assets:child-motion-demo -- --live` 返回缺少 VectorEngine 配置 - 现象:热身关“挥动左手 / 挥动右手”阶段,用户只是手自然下垂、横向小幅抖动,或挥了相反侧手,也可能被判定通过
- 原因:儿童动作 Demo 的真实背景图使用 VectorEngine `gpt-image-2-all` 生成,脚本只读取 `VECTOR_ENGINE_BASE_URL``VECTOR_ENGINE_API_KEY` 和可选 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS`;仓库内不能提交真实 key缺配置时页面只能使用 CSS 草地绘本兜底 - 原因:本地 mocap 的 handedness 当前按摄像头视角输出,不能直接当作用户身体左/右;同时左右手阶段的目标是确认现实空间安全,需要验证手臂向外打开和上下摆动角度,不能只看手部 `x` 轨迹范围
- 处理:在本地私密环境补齐 `VECTOR_ENGINE_BASE_URL=https://api.vectorengine.ai``VECTOR_ENGINE_API_KEY`,不要把 key 写入 Git先运行 `npm run assets:child-motion-demo -- --dry-run` 核对 prompt再运行 `npm run assets:child-motion-demo -- --live` 生成默认背景图 - 处理:热身关中用户左手应消费 camera-right用户右手应消费 camera-left左右手阶段只在同侧肩肘腕外展、手腕非自然下垂、连续有效帧、横向范围、上下摆动范围、肩腕角度范围和上下方向变化全部达标时完成并记录轨迹空间包络、角度范围和最大外展距离
- 验证:生成后确认 `public/child-motion-demo/picture-book-grass-stage.webp` 存在,重新打开 `/child-motion-demo` 可看到真实绘本草地背景;`npm run check:encoding` 仍通过 - 验证:运行 `npx vitest run src\components\child-motion-demo\ChildMotionWarmupDemo.test.tsx src\components\child-motion-demo\childMotionWarmupModel.test.ts`,确认相反侧手、自然下垂、单纯横向轨迹不会完成,真实展开上下摆动可以完成
- 关联:`src/components/child-motion-demo/ChildMotionWarmupDemo.tsx``src/components/child-motion-demo/childMotionWarmupModel.ts``docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md`
## 儿童动作 Demo 角色轮廓抽搐先查 mocap 坐标防抖和渲染分层
- 现象:`/child-motion-demo` 中间半透明小人在真实硬件驱动下左右轻微来回摆,移动过程中看起来忽大忽小,用户很难稳定停在目标圆环内。
- 原因:`general.body.center_norm.x` 原始值逐包直接写入 `avatarX` 时,硬件坐标小噪声会直接驱动位置保持判定和 CSS 动画;如果角色外层同时承担横向定位和跳跃 `transform`,半透明 PNG 在移动时也更容易出现重采样抖动观感。
- 处理mocap 身体中心进入角色位置前必须先 clamp再经过小幅死区、低通阻尼和单包最大步长限制键盘 A/D 调试输入仍保持即时。角色 DOM 外层只负责横向定位,内层 sprite 负责轮廓图和跳跃位移,避免同一层 `transform` 同时表达多种运动。
- 验证:运行 `npx vitest run src\components\child-motion-demo\ChildMotionWarmupDemo.test.tsx src\components\child-motion-demo\childMotionWarmupModel.test.ts src\services\useMocapInput.test.ts src\services\child-motion-demo\childMotionDebugInput.test.ts`,并用真实硬件进入站位阶段观察小幅身体晃动不会导致角色频繁左右跳动。
- 关联:`src/components/child-motion-demo/ChildMotionWarmupDemo.tsx``src/index.css``docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md`
## 宝贝识物选篮误触发先查多套判定和残余轨迹
- 现象:`宝贝识物` 运行态打开礼物盒或反馈结束后,当前物品被连续送入左侧或右侧篮子,或硬件动作名偶发命中导致未做明确横移动作也触发选篮。
- 原因:选篮如果同时消费 `wave_left_hand` / `wave_right_hand` / `wave` 动作名和手部轨迹,或在 `correct` / `wrong` 反馈阶段继续累计手部路径,会把抓握、反馈期间残留移动或未知侧别手部误算成下一次选篮。
- 处理:宝贝识物选篮只使用明确 `leftHand` / `rightHand` 的连续横向轨迹阈值;侧别为 `unknown` 的手部轨迹不参与选篮;反馈阶段清空轨迹,不在非 `active` 阶段累计路径。进入关卡和每次正确反馈结束后自动弹出物品,不再用 `open_palm -> grab` 抓握序列激活礼物盒。
- 补充:当前本地 mocap 的 handedness 是摄像头视角,宝贝识物选篮前需要换算为用户身体视角;`rightHand` 轨迹代表玩家左手并进入左篮,`leftHand` 轨迹代表玩家右手并进入右篮。键鼠调试不走该换算,仍保持鼠标左键=左篮、右键=右篮。
- 验证:运行 `npm run test -- src/components/edutainment-runtime/BabyObjectMatchRuntimeShell.test.tsx src/services/useMocapInput.test.ts`,确认动作名负向测试、未知侧别负向测试和左右手横向轨迹测试通过。
- 关联:`src/components/edutainment-runtime/BabyObjectMatchRuntimeShell.tsx``docs/technical/BABY_OBJECT_MATCH_CREATION_PUBLISH_IMPLEMENTATION_2026-05-11.md`
## 宝贝爱画左右手反了先查 mocap 摄像头视角换算
- 现象:`宝贝爱画` 中真实硬件下左手指示器和右手画笔表现反向,用户抬右手却出现左手选色指示器,或抬左手却驱动画笔 / 橡皮。
- 原因:本地 mocap 的 handedness 当前按摄像头视角输出,不能直接当成用户身体左 / 右;宝贝爱画初版直接消费 `latestCommand.leftHand/rightHand`,漏做摄像头视角到用户身体视角的换算。
- 处理:宝贝爱画运行态消费 mocap 前先换算:`rightHand` 作为用户左手,用于颜色悬停和左手指示器;`leftHand` 作为用户右手,用于画笔 / 橡皮光标、绘制、擦除和工具切换。键鼠调试输入不做该换算,继续保持鼠标左键为左手、右键为右手。
- 验证:运行 `npm run test -- src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.test.tsx src/components/edutainment-runtime/babyLoveDrawingModel.test.ts`,确认 camera-left 驱动用户右手画笔、camera-right 渲染用户左手选色指示器。
- 关联:`src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.tsx``docs/technical/BABY_LOVE_DRAWING_RUNTIME_DEMO_IMPLEMENTATION_2026-05-13.md`
## 宝贝识物创作卡在准备结果页先查长耗时 image-2 请求
- 现象:`/creation/baby-object-match` 创作生成停在“准备结果页”,约 3 分钟后显示“生成失败 / 请求超时”;后端日志可能出现同一路由 `status=502 latency_ms=231291`,或前端已失败但后端稍后返回 200。
- 原因:宝贝识物一次创作会生成 2 张物品图和 `background``ui-frame``gift-box``basket``smoke-puff` 5 张视觉包装图。旧前端只等待 180 秒并对长耗时 POST 自动重试,容易在 VectorEngine 仍在生成时先 abort再重复发起第二次生成上游某张图超过后端 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS` 或返回 5xx 时会表现为 502。
- 处理:`babyObjectMatchClient``/api/creation/edutainment/baby-object-match/assets` 使用 10 分钟超时并取消自动重试;后端并发启动物品图和视觉主题包生成,并把该路由的 VectorEngine 单图请求等待预算提升到至少 8 分钟,按资源类别输出开始、完成和耗时日志。
- 验证:运行 `npm run test -- src/services/edutainment-baby-object/babyObjectMatchClient.test.ts src/services/miniGameDraftGenerationProgress.test.ts``cargo test -p api-server edutainment_baby_object --manifest-path server-rs/Cargo.toml` 和编码检查;真实联调时查看 `宝贝识物 image-2 资源生成完成` 耗时是否小于前端超时,若仍 502 再看 `VectorEngine 图片生成上游错误``upstreamStatus/raw_excerpt`
- 关联:`src/services/edutainment-baby-object/babyObjectMatchClient.ts``src/services/miniGameDraftGenerationProgress.ts``server-rs/crates/api-server/src/edutainment_baby_object.rs``docs/technical/BABY_OBJECT_MATCH_CREATION_PUBLISH_IMPLEMENTATION_2026-05-11.md`
## 寓教于乐作品和宝贝识物模板同时消失先查入口种子
- 现象:发现页“寓教于乐”分类下已发布的宝贝识物作品突然消失,同时创作界面模板选项中也看不到或无法正常展示 `宝贝识物`
- 原因:创作入口配置事实源已迁到 SpacetimeDB `creation_entry_type_config`;前端用 `baby-object-match` 入口可见性同时控制创作模板展示和发现页宝贝识物公开作品合入。若默认种子或后台配置缺少 `baby-object-match` 行,两条链路会一起被判定为不可见。
- 处理:确认 `server-rs/crates/spacetime-module/src/runtime/creation_entry_config.rs` 默认种子包含 `id=baby-object-match``title=宝贝识物``visible=true``open=true``sort_order=90`api-server 测试降级配置也要同步包含该类型。入口图片路径需指向真实存在资源,避免卡片图片 404。
- 验证:运行 `cargo test -p module-runtime default_creation_entry_types_include_baby_object_match --manifest-path server-rs/Cargo.toml``cargo test -p api-server test_creation_entry_config_response_keeps_baby_object_match_visible --manifest-path server-rs/Cargo.toml``cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml``npm run test -- src/components/platform-entry/platformEntryCreationTypes.test.ts`
- 关联:`server-rs/crates/spacetime-module/src/runtime/creation_entry_config.rs``server-rs/crates/api-server/src/creation_entry_config.rs``docs/technical/NEW_WORK_ENTRY_CONFIG_2026-05-01.md`
## 儿童动作 Demo 绘本风资源未生成先查 VectorEngine 配置
- 现象:`/child-motion-demo` 已经呈现绘本草地风格,但 `public/child-motion-demo/picture-book-grass-stage.png``picture-book-grass-floor.png``picture-book-ground-ring.png``picture-book-character-outline.png``picture-book-ui-panel.png``picture-book-ui-button.png` 不存在Network 里对应图片返回 404或运行 `npm run assets:child-motion-demo -- --live` 返回缺少 VectorEngine 配置。
- 原因:儿童动作 Demo 的真实背景、地面、UI、地面指示环和角色轮廓资源都使用 VectorEngine `gpt-image-2-all` 生成,脚本只读取 `VECTOR_ENGINE_BASE_URL``VECTOR_ENGINE_API_KEY` 和可选 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS`;仓库内不能提交真实 key缺配置时页面只能使用 CSS 草地绘本兜底。
- 处理:在本地私密环境补齐 `VECTOR_ENGINE_BASE_URL=https://api.vectorengine.ai``VECTOR_ENGINE_API_KEY`,不要把 key 写入 Git先运行 `npm run assets:child-motion-demo -- --dry-run` 核对 prompt再运行 `npm run assets:child-motion-demo -- --live``npm run assets:child-motion-demo -- --live --only ui-panel` 等小批量命令生成资源。透明资源的品红底源图写入 `tmp/child-motion-demo-assets/`,不要把源图或预览图放入 `public/child-motion-demo/` 作为正式资产。
- 验证:生成后确认 `public/child-motion-demo/` 只保留页面引用的最终 PNG重新打开 `/child-motion-demo` 可看到真实绘本草地背景、地面、圆环、角色轮廓和 UI 资源;`npm run check:encoding` 仍通过。
- 关联:`scripts/generate-child-motion-demo-assets.mjs``src/index.css``docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md` - 关联:`scripts/generate-child-motion-demo-assets.mjs``src/index.css``docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md`
## 儿童动作 Demo 绘本资源变形先查用途拆分和透明后处理
- 现象:`/child-motion-demo` 背景风格正确,但底部草坪被拉成厚色块、顶部 HUD 或右下状态条像方形面板被横向拉伸,或旧 `picture-book-ui-panel.png` 与新资源叠在一起。
- 原因:早期资源中 `picture-book-ui-panel.png` 是接近方形画布,`picture-book-grass-floor.png` 也含大量透明边界;若 CSS 用 `background-size: 100% 100%` 把同一资源强行铺成 HUD、状态条、开始面板或底部地板就会出现变形和层叠观感。
- 处理:使用 v2 用途专属资源:`picture-book-foreground-grass-v2.png``picture-book-ground-ring-v2.png``picture-book-character-outline-v2.png``picture-book-hud-strip-v2.png``picture-book-calibration-strip-v2.png``picture-book-start-panel-v2.png``picture-book-ui-button-v2.png`CSS 按资源比例等比缩放底部草坪只覆盖下沿HUD / 状态条 / 开始托盘分别引用各自资源。若只需修透明裁切或品红边,运行 `npm run assets:child-motion-demo -- --live --postprocess-only --force --only <asset-id>`,不重新请求 image-2。
- 验证:用横屏截图检查没有新旧资源叠加、没有方形面板拉成长条、角色和地面指示环不被前景草坪埋住;同时运行 `npm run check:encoding`
- 关联:`scripts/generate-child-motion-demo-assets.mjs``src/index.css``public/child-motion-demo/``docs/technical/CHILD_MOTION_DEMO_WARMUP_IMPLEMENTATION_SPEC_2026-05-09.md`
## GPT-image-2 不再读 APIMart 图片配置 ## GPT-image-2 不再读 APIMart 图片配置
- 现象:配置了 `APIMART_BASE_URL` / `APIMART_API_KEY`RPG、拼图或方洞的 GPT-image-2 生图仍返回缺配置,或请求体里还出现 `official_fallback` / `image_urls` - 现象:配置了 `APIMART_BASE_URL` / `APIMART_API_KEY`RPG、拼图或方洞的 GPT-image-2 生图仍返回缺配置,或请求体里还出现 `official_fallback` / `image_urls`
@@ -91,6 +182,46 @@
- 验证:后端单测应覆盖 `images/edits` 路由、`b64_json` 响应解码和参考图强提示;真实联调先看日志里是否命中 `拼图 VectorEngine 图片编辑 HTTP 返回` - 验证:后端单测应覆盖 `images/edits` 路由、`b64_json` 响应解码和参考图强提示;真实联调先看日志里是否命中 `拼图 VectorEngine 图片编辑 HTTP 返回`
- 关联:`server-rs/crates/api-server/src/puzzle.rs``src/services/puzzleReferenceImage.ts``docs/technical/VECTOR_ENGINE_GPT_IMAGE_2_GENERATION_2026-05-09.md` - 关联:`server-rs/crates/api-server/src/puzzle.rs``src/services/puzzleReferenceImage.ts``docs/technical/VECTOR_ENGINE_GPT_IMAGE_2_GENERATION_2026-05-09.md`
## 拼图 edits 报 error sending request 先看网络分类
- 现象:拼图有参考图时返回 `拼图图片生成失败:创建拼图 VectorEngine 图片编辑任务失败error sending request for url (https://api.vectorengine.ai/v1/images/edits)`,后端没有 `拼图 VectorEngine 图片编辑 HTTP 返回` 日志。
- 原因:这是 `reqwest``send()` 阶段失败,尚未收到 VectorEngine HTTP 响应;常见原因是服务器网络 / DNS / 防火墙 / 代理问题,或上游网关中断 multipart 连接。
- 处理:查看错误响应 `details.reason/source/connect/body/timeout/endpoint``拼图 VectorEngine 请求发送失败` 日志。拼图图片客户端已强制 HTTP/1.1,降低 multipart HTTP/2 兼容风险;若 `connect=true` 先查网络出口,若 `body=true` 先查参考图大小和 multipart 发送。
- 验证:`curl -i -X POST https://api.vectorengine.ai/v1/images/edits -H "Authorization: Bearer invalid" -F "model=gpt-image-2-all" -F "prompt=test" -F "n=1" -F "size=1024x1024"` 至少应返回 HTTP `401`说明域名、TLS 和路径可达;执行 `cargo test -p api-server puzzle_vector_engine --manifest-path server-rs/Cargo.toml`
- 关联:`server-rs/crates/api-server/src/puzzle.rs``docs/technical/VECTOR_ENGINE_GPT_IMAGE_2_GENERATION_2026-05-09.md``docs/technical/API_SERVER_EXTERNAL_SERVICE_ENV_CONFIG_2026-05-07.md`
## 拼图自动试玩缺 UI 背景先查本地运行态字段继承
- 现象:拼图草稿生成完成后,草稿数据里已有首关 `uiBackgroundImageSrc`,结果页素材配置也能看到背景图,但自动试玩或结果页“试玩”进入局内仍只显示封面模糊背景,甚至看不到 UI 背景。
- 原因:生成完成后的自动试玩走前端 `startLocalPuzzleRun(...)` 本地运行态兜底,不经过后端 `start_puzzle_run`;如果本地 run 只把 `coverImageSrc` 带入 `currentLevel`,就会丢掉 `levels[].uiBackgroundImageSrc``levels[].backgroundMusic`
- 处理:`startLocalPuzzleRun` 与本地下一关 handoff 都要从关卡 `levels[]` 复制 `uiBackgroundImageSrc``backgroundMusic``currentLevel``PuzzleRuntimeShell` 继续读取 `currentLevel.uiBackgroundImageSrc` 渲染全屏背景。
- 验证:`npm run test -- src/services/puzzle-runtime/puzzleLocalRuntime.test.ts src/components/puzzle-runtime/PuzzleRuntimeShell.test.tsx src/components/puzzle-result/PuzzleResultView.test.tsx`
- 关联:`src/services/puzzle-runtime/puzzleLocalRuntime.ts``src/components/puzzle-runtime/PuzzleRuntimeShell.tsx``src/components/puzzle-result/PuzzleResultView.tsx``docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md`
## 拼图草稿生成后音乐/UI 又变空先查结果页回包合并
- 现象拼图草稿生成完成后音乐面板曲名有值但音频槽仍显示“暂无音乐”UI 仍展示默认预览;试玩进入局内也没有生成音乐或 UI 背景。
- 原因:结果页若已有本地 `generationStatus = generating` 编辑态,后端生成完成回包会走 `mergeDraftEditStateWithIncomingState(...)` 合并。该合并必须把生成候选图、正式图、`uiBackground*``backgroundMusic` 作为同一批生成资产处理;漏掉 `backgroundMusic` 时,随后自动保存会把空音乐写回 `levels_json`
- 处理:`PuzzleResultView` 合并生成完成回包时同步保留 `backgroundMusic`,并用回归测试覆盖 UI 预览、音乐试听和试玩 payload 都读取最新 `levels[]` 资产。
- 验证:`npm run test -- src/components/puzzle-result/PuzzleResultView.test.tsx`,以及自动试玩入口测试 `npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "puzzle draft generation auto starts trial"`
- 关联:`src/components/puzzle-result/PuzzleResultView.tsx``src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx``docs/technical/PUZZLE_MATCH3D_RESULT_AUDIO_TAB_2026-05-11.md`
## 自动草稿成功但缺音乐或 UI 先查后端吞错
- 现象:拼图或抓大鹅生成页提示完成,但草稿页仍显示“暂无音乐”,拼图 UI 仍是默认预览,试玩局内也没有生成音乐或 UI 背景。
- 原因:自动草稿阶段如果把 VectorEngine / Suno / OSS / 资产绑定错误记录为 warning 后继续返回成功,前端只能拿到缺关键资产的成功 draft随后保存和试玩都会消费这份空资产状态。
- 处理:自动草稿必须把必需生成资产当作后端完成条件:拼图首关需同时具备 `levels[0].backgroundMusic.audioSrc``levels[0].uiBackgroundImageSrc/uiBackgroundImageObjectKey`;抓大鹅需在 `generatedItemAssets[]` 中具备非空 `backgroundMusic.audioSrc`。缺失或上游失败时返回错误并停留在生成页,结果页手动重新生成只作为已有草稿补救入口。
- 验证:`cargo test -p api-server puzzle_initial_draft_assets_must_include_music_and_ui_background match3d_background_music_ready_requires_audio_src match3d_background_music_title_is_required_for_auto_draft --manifest-path server-rs\Cargo.toml`,并重启 `npm run api-server` 后检查 `/healthz`
- 关联:`server-rs/crates/api-server/src/puzzle.rs``server-rs/crates/api-server/src/match3d.rs``docs/technical/PUZZLE_FORM_CREATION_FLOW_2026-04-29.md``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 拼图草稿生成 180 秒后 502/504 先查 VectorEngine 超时与前端重试
- 现象:点击“生成拼图游戏草稿”后,`POST /api/runtime/puzzle/agent/sessions/{sessionId}/actions` 等待约 180 秒返回 `502 Bad Gateway``504 Gateway Timeout`;钱包流水里同一 session 可能出现连续两组 `puzzle_initial_image` 扣费后退款。
- 原因:首图生成走 VectorEngine `gpt-image-2-all`,默认 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS=180000`;若上游在该窗口内未返回,后端退款并返回超时错误。旧前端 action 写请求会对 502/503/504 自动重试一次,导致同一次点击重复触发生图与扣退费。
- 处理:拼图/创作 Agent 的 `executeAction` 默认不做前端自动重试;后端将 VectorEngine / 图片请求超时映射为 `504 Gateway Timeout``error.details.provider=vector-engine``timeout=true`。真实排障按日志同一 `session_id``拼图 VectorEngine 图片生成 HTTP 返回` 是否缺失,以及钱包流水扣费到退款的时间差是否接近 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS`
- 验证:运行 `npm run test -- src/services/creation-agent/creationAgentClientFactory.test.ts src/services/apiClient.test.ts``cargo test -p api-server puzzle_vector_engine --manifest-path server-rs/Cargo.toml`,真实联调重启 `npm run api-server` 后检查 `/healthz`
- 关联:`src/services/creation-agent/creationAgentClientFactory.ts``server-rs/crates/api-server/src/puzzle.rs``docs/technical/API_SERVER_EXTERNAL_SERVICE_ENV_CONFIG_2026-05-07.md`
## 旧后端路线文档造成判断漂移 ## 旧后端路线文档造成判断漂移
- 现象:开发时参考到 Express、Node、PostgreSQL 或 Go 方向旧文档,导致接口、数据真相或部署路径与当前主线不一致。 - 现象:开发时参考到 Express、Node、PostgreSQL 或 Go 方向旧文档,导致接口、数据真相或部署路径与当前主线不一致。
@@ -143,8 +274,8 @@
- 现象:本地 `npm run dev``3101` 已占用、重复发布 SpacetimeDB wasm 编译太慢,或只想检查 `spacetime-module` 语法而被完整联调链路拖慢。 - 现象:本地 `npm run dev``3101` 已占用、重复发布 SpacetimeDB wasm 编译太慢,或只想检查 `spacetime-module` 语法而被完整联调链路拖慢。
- 原因:`npm run dev` 默认同时启动 SpacetimeDB standalone、发布 `server-rs/crates/spacetime-module`、启动 Rust `api-server`、主站 Vite 与后台 Vite并非每个阶段都需要完整重启和重新发布。 - 原因:`npm run dev` 默认同时启动 SpacetimeDB standalone、发布 `server-rs/crates/spacetime-module`、启动 Rust `api-server`、主站 Vite 与后台 Vite并非每个阶段都需要完整重启和重新发布。
- 处理:`npm run dev` 启动后会把实际 SpacetimeDB URL 记录到 `server-rs/.spacetimedb/local/data/dev-rust-spacetime-url`。下次启动即使没有传 `--skip-spacetime`,脚本也会先检查 `spacetime.pid` 对应进程和该 URL 是否在线;在线则直接复用现有宿主。确认需要新启动 SpacetimeDB 时,脚本先检测 `3101`,被占用则输出占用进程并选择最近可用端口,保证 publish 与 `api-server` 都连接同一个实际 SpacetimeDB URL。`api-server` 启动前也会检测 `8082` 并选择最近可用端口。Windows / Git Bash 下不要用 `tr/head/xargs` 管道读取 `spacetime.pid` 或 URL 记录,脚本应使用 Node 读取并短重试,避免 `tr: read error: Device or resource busy`;未修改 `spacetime-module` 时使用 `npm run dev -- --skip-publish`;只查模块语法时执行 `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml``npm run dev` 会在启动前检查 SpacetimeDB、api-server、主站 Vite、后台 Vite 端口,不可用时自动寻找后续可用端口,并把实际端口传给 publish、后端环境变量和前端代理目标。 - 处理:`npm run dev` 启动后会把实际 SpacetimeDB URL 记录到 `server-rs/.spacetimedb/local/data/dev-rust-spacetime-url`。下次启动即使没有传 `--skip-spacetime`,脚本也会先检查 `spacetime.pid` 对应进程和该 URL 是否在线;在线则直接复用现有宿主。确认需要新启动 SpacetimeDB 时,脚本先检测 `3101`,被占用则输出占用进程并选择最近可用端口,保证 publish 与 `api-server` 都连接同一个实际 SpacetimeDB URL。显式传 `--skip-spacetime` 时表示复用既有宿主,脚本不再对 SpacetimeDB 端口做可用性漂移;`--spacetime-port 3101` 就是后端要连接的实际端口,避免被误改到空闲但未启动的 `3102``api-server` 启动前也会检测 `8082` 并选择最近可用端口。Windows / Git Bash 下不要用 `tr/head/xargs` 管道读取 `spacetime.pid` 或 URL 记录,脚本应使用 Node 读取并短重试,避免 `tr: read error: Device or resource busy`;未修改 `spacetime-module` 时使用 `npm run dev -- --skip-publish`;只查模块语法时执行 `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml``npm run dev` 会在启动前检查 SpacetimeDB、api-server、主站 Vite、后台 Vite 端口,不可用时自动寻找后续可用端口,并把实际端口传给 publish、后端环境变量和前端代理目标。
- 验证:`--skip-spacetime` 后脚本复用现有 `http://127.0.0.1:3101``3101``8082` 被其他进程占用时,脚本输出占用进程并使用最近可用端口;`--skip-publish` 后不再进入 publish 阶段;`cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml` 能完成 Rust 语法和类型检查。端口漂移时控制台会打印 `[dev:ports] ... 不可用,改用 ...`,后续 `[dev:rust] web/admin web/rust api/spacetime` 地址应与实际端口一致。 - 验证:`--skip-spacetime` 后脚本复用现有 `http://127.0.0.1:3101`日志中的 `[dev:rust] spacetime:` 不应漂移到没有服务的 `3102``GET /api/creation-entry/config` 不应返回连接空端口导致的 `502``3101``8082` 被其他进程占用时,脚本输出占用进程并使用最近可用端口;`--skip-publish` 后不再进入 publish 阶段;`cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml` 能完成 Rust 语法和类型检查。端口漂移时控制台会打印 `[dev:ports] ... 不可用,改用 ...`,后续 `[dev:rust] web/admin web/rust api/spacetime` 地址应与实际端口一致。
- 关联:`docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md``scripts/dev-rust-stack.sh` - 关联:`docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md``scripts/dev-rust-stack.sh`
## 本地 SpacetimeDB publish 401 可清本地库重发 ## 本地 SpacetimeDB publish 401 可清本地库重发
@@ -195,6 +326,13 @@
- 验证:本地加入临时测试后,`HYPER3D_API_KEY` 应能被 `.env.secrets.local` 覆盖,且 shell 变量仍然最高优先级。 - 验证:本地加入临时测试后,`HYPER3D_API_KEY` 应能被 `.env.secrets.local` 覆盖,且 shell 变量仍然最高优先级。
- 关联:`scripts/api-server-dev.mjs``server-rs/crates/api-server/src/hyper3d_generation.rs``docs/technical/HYPER3D_RODIN_GEN2_MODEL_GENERATION_2026-05-08.md` - 关联:`scripts/api-server-dev.mjs``server-rs/crates/api-server/src/hyper3d_generation.rs``docs/technical/HYPER3D_RODIN_GEN2_MODEL_GENERATION_2026-05-08.md`
## OSS 密钥键名不要把字母 O 写成数字 0
- 现象:`.env.secrets.local` 看起来已经配置 OSS AccessKey Secret但拼图或抓大鹅生成仍返回 `OSS 未完成环境变量配置`
- 原因:后端只读取 `ALIYUN_OSS_ACCESS_KEY_SECRET`。如果写成 `ALIYUN_0SS_ACCESS_KEY_SECRET`,中间是数字 `0`,配置合并检查会显示正确键缺失,`api-server` 不会初始化 OSS 客户端。另一个常见原因是外层 shell / IDE 预置了空的 `ALIYUN_OSS_*`,旧启动脚本会把空值当作最高优先级,导致 `.env.local``.env.secrets.local` 的真实值被跳过。
- 处理:只改键名为 `ALIYUN_OSS_ACCESS_KEY_SECRET`,保留原值;不要在日志、文档或对话里输出密钥内容。本地启动脚本应只保护非空外层环境变量,空字符串或全空白值不得遮蔽本地 env 文件。
- 验证:运行 `npm run check:api-server-env`,确认 `VECTOR_ENGINE_BASE_URL``VECTOR_ENGINE_API_KEY``ALIYUN_OSS_BUCKET``ALIYUN_OSS_ENDPOINT``ALIYUN_OSS_ACCESS_KEY_ID``ALIYUN_OSS_ACCESS_KEY_SECRET` 都是 `present`,再重启 `npm run api-server``npm run dev`
## 拼图图片生成 98% 后报 OSS V4 签名时间格式化失败 ## 拼图图片生成 98% 后报 OSS V4 签名时间格式化失败
- 现象:拼图创作表单生成进度卡在 98%`POST /api/runtime/puzzle/agent/sessions/{sessionId}/actions` 返回 `502 Bad Gateway`,前端提示 `拼图图片生成失败OSS V4 签名时间格式化失败` - 现象:拼图创作表单生成进度卡在 98%`POST /api/runtime/puzzle/agent/sessions/{sessionId}/actions` 返回 `502 Bad Gateway`,前端提示 `拼图图片生成失败OSS V4 签名时间格式化失败`
@@ -405,6 +543,22 @@
- 验证:发布链路使用当前 `deploy/systemd``deploy/nginx``scripts/deploy``jenkins/Jenkinsfile.production-*` - 验证:发布链路使用当前 `deploy/systemd``deploy/nginx``scripts/deploy``jenkins/Jenkinsfile.production-*`
- 关联:`docs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md` - 关联:`docs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md`
## Release Web 产物通过内网 rsync 拉取
- 现象:`Genarrative-Web-Deploy` 发布到 `release` 目标时release agent 本地没有 `/var/cache/genarrative-build/web-artifacts/<job>/<build>/<version>/web.tar.gz`,但 Jenkins controller 又只归档轻量元数据,导致发布阶段找不到 Web 大包。
- 原因Web 大包为了避免从 Linux 构建机拉回 Jenkins controller默认留在构建机稳定缓存目录development 目标与构建机同机可直接读取release 目标是独立机器,需要内网同步。
- 处理release 服务器的 Jenkins 运行用户配置 SSH Host `genarrative-build-internal` 指向构建机内网地址,`Genarrative-Web-Deploy``DEPLOY_TARGET=release` 且本地缺少大包时默认执行 `rsync` 拉取同一路径内容;真实内网 IP、用户和私钥路径只放在服务器本机 SSH config不写入 Jenkinsfile。
- 验证:在 release 服务器上先手工跑通 `rsync -av --progress "genarrative-build-internal:${SRC}/" "${DST}/"`,再运行 Web Deploy流水线会继续执行 `web.tar.gz.sha256` 校验。
- 关联:`jenkins/Jenkinsfile.production-web-deploy``docs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md`
## Jenkins 生产流水线拉 Git 先本机再域名备用
- 现象:生产发布、数据库导入导出或服务器配置流水线在目标 Linux agent 上执行 `GitSCM checkout` 时,`http://127.0.0.1:3000/GenarrativeAI/Genarrative.git` 不可达,导致脚本还没拉下来就失败;若 fallback 到公网 Git 时没有限制 refspec、浅克隆和 tags还可能在约 10 分钟后出现 `git-remote-https died of signal 15``early EOF``invalid index-pack output`
- 原因:`127.0.0.1` 只代表当前执行阶段的 agent 自身;当 release agent 与 Git 服务不在同一台机器,或本机 Git/Web 服务临时不可用时,固定写死 localhost 会阻断 Jenkinsfile 内部源码/脚本 checkout。
- 处理Jenkins Job 的 `Pipeline script from SCM` 由 Windows controller 执行SCM URL 使用公网域名 `https://git.genarrative.world/GenarrativeAI/Genarrative.git`。运行于 Linux agent 的 Jenkinsfile 首次 `checkout([$class: 'GitSCM', ...])` 层先尝试 `GIT_REMOTE_URL=http://127.0.0.1:3000/GenarrativeAI/Genarrative.git`,失败后直接尝试 `GIT_REMOTE_FALLBACK_URL=https://git.genarrative.world/GenarrativeAI/Genarrative.git`,不再配置内网 IP fallback首次 checkout 必须使用目标分支 refspec、`CloneOption shallow=true depth=1 noTags=true honorRefspec=true`。后续统一走 `scripts/jenkins-checkout-source.sh`,该脚本也按主地址、域名备用地址顺序重新 fetch 并把 `origin` 切到实际可用地址;`COMMIT_HASH` 为空时继续 `--depth=1 --no-tags`,只有指定 commit 时才允许加深历史做分支归属校验。
- 验证:扫描本地 Jenkins live job `config.xml`,确认 SCM `<url>` 都是 `https://git.genarrative.world/GenarrativeAI/Genarrative.git`;扫描所有以 `127.0.0.1:3000` 拉 Git 且运行在 Linux agent 的生产 Jenkinsfile确认存在 `GIT_REMOTE_FALLBACK_URL``EFFECTIVE_GIT_REMOTE_URL` 和脚本层 `GIT_REMOTE_FALLBACK_URL` 透传;运行 `bash -n scripts/jenkins-checkout-source.sh`
- 关联:`jenkins/Jenkinsfile.production-web-deploy``jenkins/Jenkinsfile.production-api-deploy``jenkins/Jenkinsfile.production-stdb-module-publish``jenkins/Jenkinsfile.production-server-provision``jenkins/Jenkinsfile.production-database-export``jenkins/Jenkinsfile.production-database-import``scripts/jenkins-checkout-source.sh``docs/technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md`
## Jenkins 可选参数在 set -u 下不能裸读 ## Jenkins 可选参数在 set -u 下不能裸读
- 现象:数据库导入或导出流水线报 `INCLUDE_TABLES: unbound variable`,或其它可选参数在 Bash 中未定义即退出。 - 现象:数据库导入或导出流水线报 `INCLUDE_TABLES: unbound variable`,或其它可选参数在 Bash 中未定义即退出。
@@ -424,9 +578,9 @@
## 拼图发布 409 不一定是接口故障 ## 拼图发布 409 不一定是接口故障
- 现象:拼图结果页点击发布后,控制台出现 `POST /api/runtime/puzzle/agent/sessions/{sessionId}/actions 409 (Conflict)`,用户只看到发布失败。 - 现象:拼图结果页点击发布后,控制台出现 `POST /api/runtime/puzzle/agent/sessions/{sessionId}/actions 409 (Conflict)`,用户只看到发布失败。
- 原因:`publish_puzzle_work` 是资产操作发布入口,发布前会预扣 `1`点;余额不足时后端按业务冲突返回 `409 CONFLICT``details.message``点余额不足` - 原因:`publish_puzzle_work` 是资产操作发布入口,发布前会预扣 `1`点;余额不足时后端按业务冲突返回 `409 CONFLICT``details.message``点余额不足`
- 处理:前端发布弹窗在用户点击发布后必须保留并展示后端业务错误,不能只把错误写到弹窗背后的页面 banner。 - 处理:前端发布弹窗在用户点击发布后必须保留并展示后端业务错误,不能只把错误写到弹窗背后的页面 banner。
- 验证:`PuzzleResultView` 单测覆盖发布弹窗内展示 `点余额不足` - 验证:`PuzzleResultView` 单测覆盖发布弹窗内展示 `点余额不足`
- 关联:`src/components/puzzle-result/PuzzleResultView.tsx``docs/technical/PUZZLE_RESULT_AUTOSAVE_AND_TAG_GATE_FIX_2026-04-28.md``docs/technical/ASSET_GENERATION_POINTS_CONSUMPTION_2026-04-27.md` - 关联:`src/components/puzzle-result/PuzzleResultView.tsx``docs/technical/PUZZLE_RESULT_AUTOSAVE_AND_TAG_GATE_FIX_2026-04-28.md``docs/technical/ASSET_GENERATION_POINTS_CONSUMPTION_2026-04-27.md`
## WebGL 画布在高 DPR 移动端放大溢出 ## WebGL 画布在高 DPR 移动端放大溢出
@@ -445,46 +599,85 @@
- 验证:`cargo test -p api-server accepts_opaque_subscription_key_without_length_cap --manifest-path server-rs/Cargo.toml` - 验证:`cargo test -p api-server accepts_opaque_subscription_key_without_length_cap --manifest-path server-rs/Cargo.toml`
- 关联:`server-rs/crates/api-server/src/hyper3d_generation.rs``docs/technical/HYPER3D_RODIN_GEN2_MODEL_GENERATION_2026-05-08.md` - 关联:`server-rs/crates/api-server/src/hyper3d_generation.rs``docs/technical/HYPER3D_RODIN_GEN2_MODEL_GENERATION_2026-05-08.md`
## 抓大鹅草稿生成恢复 Rodin 后要并行生成模型、同步长超时和 GLB 私有读取 ## 抓大鹅草稿不要再接回 Rodin GLB 生成
- 现象:抓大鹅草稿生成重新接回 Rodin 后,前端可能在模型轮询和 GLB 转存完成前超时;或 Hyper3D 控制台显示 3 个任务已完成,但草稿进度页仍停留在 `生成3D模型`;或结果页把 `/generated-match3d-assets/.../model.glb` 直接当浏览器 URL 加载导致私有 OSS/CORS 读取失败 - 现象:修改抓大鹅素材时容易沿用旧 Rodin/GLB 方案,导致新草稿生成耗时变长、进度停在模型阶段,或运行态等待不存在的 GLB
- 原因:`match3d_compile_draft` 会完成作品元信息、素材图、切图上传、3 件 Rodin 图生模型、GLB 下载和 OSS 转存,耗时远长于普通 Agent action如果 3 件 Rodin 模型逐个提交和轮询,等待时间会线性叠加;同时 generated 私有资产不能被 Three.js 直接 `fetch` - 原因:仓库里保留了 Hyper3D 通用代理和历史模型字段,旧文档也曾要求草稿阶段同步生成 GLB。当前产品口径已经改为 2D 多视角素材
- 处理:切图和图片入库后,所有 Rodin 图生模型任务必须并行提交、并行轮询、并行下载转存Match3D creation client 的 `executeAction` 必须给长超时,当前为 20 分钟;生成进度页要包含 `生成3D模型` 阶段,但它不是 Hyper3D task 订阅页,而是在长 action 执行期间旁路轮询 session / work detail并用 profile 的 `generatedItemAssets` 更新完成数量;控制台看到 Rodin `Done` 后仍需等待下载列表、GLB 下载、OSS 转存和草稿 JSON 写回。结果页模型预览、场内运行态和备选栏预览都必须通过 `/api/assets/read-bytes` 读取 GLB 字节后交给 Three.js GLTFLoader不要直接请求裸 generated 路径。排查时按同一个 session/profile 查看 api-server 日志:`抓大鹅 Rodin 状态轮询返回``抓大鹅 Rodin 下载列表轮询返回``抓大鹅 Rodin GLB 下载完成``抓大鹅 Rodin GLB 转存 OSS 完成`;同时检查前端 work detail 响应里的 `generatedItemAssets[].status/modelObjectKey/error` - 处理:`match3d_compile_draft` 与批量新增只生成 2D 图片:每个物品 5 个视角,单张 1K 素材图固定 5x5最多承载 5 个物品,一行对应一个物品,不足 5 个物品也补齐到完整 5 行;超过 5 个物品自动分批并行生图。素材图 prompt 固定要求纯绿色绿幕背景,切割前先把绿幕处理为透明 alpha再做格内内容前景边界校准并带留白避免固定内缩切掉贴近格线的主体。`generatedItemAssets[].status` 使用 `image_ready`,发布校验看 `imageViews[]` 或首图引用。`generated-models` 仅用于历史外部模型链接转存,不能作为新生产链路
- 验证:`npm run test -- src\services\miniGameDraftGenerationProgress.test.ts src\components\match3d-result\Match3DResultView.test.tsx src\components\match3d-runtime\Match3DRuntimeShell.test.tsx``npm run typecheck`;真实联调需配置 `VECTOR_ENGINE_API_KEY``HYPER3D_API_KEY` 和 OSS 变量 - 验证:`cargo test -p api-server match3d --manifest-path server-rs/Cargo.toml``npm run test -- src\services\miniGameDraftGenerationProgress.test.ts src\components\match3d-result\Match3DResultView.test.tsx src\components\match3d-runtime\Match3DRuntimeShell.test.tsx`
- 关联:`src/services/match3d-creation/match3dCreationClient.ts``src/services/creation-agent/creationAgentClientFactory.ts``src/components/match3d-result/Match3DModelPreview.tsx``src/components/match3d-runtime/Match3DPhysicsBoard.tsx``server-rs/crates/api-server/src/match3d.rs``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md` - 关联:`server-rs/crates/api-server/src/match3d.rs``src/components/match3d-runtime/Match3DRuntimeShell.tsx``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## Rodin 完成态后下载列表可能延迟或字段漂移
- 现象:抓大鹅草稿生成时 Rodin 状态已完成,但 `/api/creation/match3d/sessions/{sessionId}/actions` 返回 502提示 `{物品名} 3D 模型已完成但未返回可下载模型文件:{taskUuid}`
- 原因Hyper3D Rodin 官方 `check-status_reset_v` 示例要求看 `jobs` 列表,只有所有 job 都 `Done` 才能进入下载;`download-results_reset_v` 还明确要求用生成响应顶层 `uuid` 作为 `task_uuid`,不要用 `jobs.uuids` 子任务 uuid。旧聚合若只看 root status 或第一个 job可能在 preview job 完成但模型 job 仍在生成时提前下载。另外任务完成和下载列表文件发布不是强同步的;上游下载结果还可能使用 `fileUrl``signedUrl``presignedUrl``fileName` 等字段别名,旧解析器只识别 `url/downloadUrl/name/file_name/filename` 时会得到空列表。
- 处理:`query_task_status` 聚合状态必须以 `jobs` 为准:任一 failed 即 failed全部 done 才 done`match3d_compile_draft` 在状态完成后对 `query_downloads` 继续轮询;下载解析兼容常见 URL 和文件名字段别名;模型选择优先 `.glb`,可兜底到非图片下载文件,但只有 preview/png/jpg/webp 这类预览图时必须继续失败,不能伪装成 GLB。
- 验证:`cargo test -p api-server match3d_model_download --manifest-path server-rs/Cargo.toml``cargo test -p api-server extracts_download_files --manifest-path server-rs/Cargo.toml``cargo test -p api-server match3d --manifest-path server-rs/Cargo.toml``cargo test -p api-server hyper3d --manifest-path server-rs/Cargo.toml`
- 关联:`server-rs/crates/api-server/src/match3d.rs``server-rs/crates/api-server/src/hyper3d_generation.rs``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 抓大鹅切图路径不能只用中文物品名 ## 抓大鹅切图路径不能只用中文物品名
- 现象:草稿页 `3D素材` Tab 中多个素材名称不同,但预览图片完全一样;点击图生模型生成时还可能提示 `参考图必须是 data URL` - 现象:草稿页 `素材配置 > 物品` 中多个素材名称不同,但预览图片完全一样。
- 原因:中文物品名经过 OSS 路径段清洗后都可能退化成 `item`,多张切割图片写到同一个 `items/item/image.png` object key后写入覆盖先写入结果页手动 Rodin 图生模型还曾把 `/generated-match3d-assets/...` 私有路径直接作为 `imageDataUrls` 提交 - 原因:中文物品名经过 OSS 路径段清洗后都可能退化成 `item`,多张切割图片写到同一个 object key后写入覆盖先写入
- 处理:切割图上传路径必须带稳定唯一 `itemId` 前缀,例如 `items/match3d-item-1-item/image.png`;结果页提交图生模型前,generated 私有路径先经同源 `/api/assets/read-bytes` 由后端换签并读取字节,前端再转成 `data:image/...;base64,...`,不要在浏览器里直接 `fetch` OSS 签名 URL否则会被 bucket CORS 拦截 - 处理:切割图上传路径必须带稳定唯一 `itemId` 前缀,例如 `items/match3d-item-1-item/views/view-01.png`;运行态读取 generated 私有图片时通过同源 `/api/assets/read-url` 换签,不直接请求裸 OSS 路径
- 验证:后端单测覆盖中文名路径唯一前端单测覆盖 generated 参考图会换签、fetch 并以 Data URL 调用 `submitHyper3dImageToModel` - 验证:后端单测覆盖中文名路径唯一前端运行态测试覆盖 generated 图片源解析
- 关联:`server-rs/crates/api-server/src/match3d.rs``src/components/match3d-result/Match3DResultView.tsx``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md` - 关联:`server-rs/crates/api-server/src/match3d.rs``src/components/match3d-result/Match3DResultView.tsx``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 抓大鹅生成素材不能只挂在 compile response ## 抓大鹅生成素材不能只挂在 compile response
- 现象:抓大鹅草稿生成完成后停留在结果页能看到切割好的 `3D素材` 图片;退出后从草稿 Tab 重新进入同一草稿,素材列表变回默认占位或为空,已生成的物品名称和图片丢失。 - 现象:抓大鹅草稿生成完成后停留在结果页能看到切割好的物品图片;退出后从草稿 Tab 重新进入同一草稿,素材列表变回默认占位或为空,已生成的物品名称和图片丢失。
- 原因:`generatedItemAssets` 如果只附加在 `match3d_compile_draft` 的 HTTP response draft 上,刷新或重进时 `getMatch3DWorkDetail` 只能读取 SpacetimeDB 中的 `match3d_work_profile`;旧 mapper 返回空数组,自然无法恢复素材。拼图链路已经通过 `save_puzzle_generated_images` 把候选图和 levels 写回 work profile抓大鹅也必须同样写持久字段。 - 原因:`generatedItemAssets` 如果只附加在 `match3d_compile_draft` 的 HTTP response draft 上,刷新或重进时 `getMatch3DWorkDetail` 只能读取 SpacetimeDB 中的 `match3d_work_profile`;旧 mapper 返回空数组,自然无法恢复素材。拼图链路已经通过 `save_puzzle_generated_images` 把候选图和 levels 写回 work profile抓大鹅也必须同样写持久字段。
- 处理compile 成功时把独立物品图片列表序列化写入 `match3d_work_profile.generated_item_assets_json``update_match3d_work` / `publish_match3d_work` 保留该字段API work summary/detail 映射反序列化为 `generatedItemAssets`。前端保持“本次 draft 优先,重进 profile 兜底”的读取顺序。 - 处理compile 成功时把独立物品图片列表序列化写入 `match3d_work_profile.generated_item_assets_json``update_match3d_work` / `publish_match3d_work` 保留该字段API work summary/detail 映射反序列化为 `generatedItemAssets`。前端保持“本次 draft 优先,重进 profile 兜底”的读取顺序。
- 验证:`cargo test -p spacetime-client match3d --manifest-path server-rs/Cargo.toml``cargo test -p api-server match3d --manifest-path server-rs/Cargo.toml``npm run test -- src/components/match3d-result/Match3DResultView.test.tsx` - 验证:`cargo test -p spacetime-client match3d --manifest-path server-rs/Cargo.toml``cargo test -p api-server match3d --manifest-path server-rs/Cargo.toml``npm run test -- src/components/match3d-result/Match3DResultView.test.tsx`
- 关联:`server-rs/crates/spacetime-module/src/match3d/*``server-rs/crates/spacetime-client/src/mapper.rs``server-rs/crates/api-server/src/match3d.rs``src/components/match3d-result/Match3DResultView.tsx``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md` - 关联:`server-rs/crates/spacetime-module/src/match3d/*``server-rs/crates/spacetime-client/src/mapper.rs``server-rs/crates/api-server/src/match3d.rs``src/components/match3d-result/Match3DResultView.tsx``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 抓大鹅试玩和正式运行态不要只读草稿页本地模型预览 ## 抓大鹅试玩和正式运行态不要只读草稿页本地素材预览
- 现象:历史草稿页 `3D素材` Tab 能看到水果模型,但点击试玩或从推荐 / 公开作品进入正式抓大鹅时,局内仍显示默认积木素材。 - 现象:结果页能看到生成的物品图片,但点击试玩或从推荐 / 公开作品进入正式抓大鹅时,局内仍显示默认积木素材。
- 原因:结果页手动 `重新生成` 曾只更新本地 `assetDrafts.downloads`,没有把新的 GLB 写回 `generatedItemAssets`;历史数据还可能只有 `modelObjectKey` 而没有 `modelSrc`;推荐流内嵌运行态若只读卡片摘要,卡片缺素材时会把已持久化 profile 模型丢掉;本次生成 response 的 draft 也可能比 profile 旧,只带图片而不带模型 - 原因:结果页本地 `assetDrafts` 和作品 profile 的 `generatedItemAssets` 可能不同步;推荐流内嵌运行态若只读卡片摘要,卡片缺素材时会把已持久化 profile 素材丢掉;点击试玩时 React state 异步更新也可能让运行态第一帧读取旧 `match3dProfile`
- 处理:结果页模型预览和运行态都按 `modelSrc || modelObjectKey` 读取;手动重新生成成功后把素材草稿重新序列化并写回作品 profile`Match3DResultView` 合并同 `itemId` 的 draft/profile 素材,用 profile 已有模型补齐旧 draft;推荐流内嵌运行态启动前若卡片摘要没有生成素材,补读 `getMatch3DWorkDetail(profileId)` 并把详情资产传给 `Match3DRuntimeShell` - 处理:删除、批量新增、音效生成或封面引用物品素材后,都把当前 `generatedItemAssets` 写回作品 profile`Match3DResultView` 合并同 `itemId` 的 draft/profile 素材,用 profile 已有 `imageViews[]`、首图引用、`backgroundMusic``backgroundAsset` 补齐旧 draft点击试玩前把试玩可用物品种类通过 `itemTypeCountOverride` 降到已生成 2D 素材数量;推荐流内嵌运行态启动前若卡片摘要没有物品图片素材,补读 `getMatch3DWorkDetail(profileId)` 并把详情资产传给 `Match3DRuntimeShell``PlatformEntryFlowShellImpl` 需要维护 `match3dRuntimeProfile`,在 `startMatch3DRunFromProfile` 创建 run 后立即锁定本次完整 profileruntime 渲染时优先按 `run.profileId` 使用这份 profile而不是等待普通 `match3dProfile` state 下一轮刷新。同 profile 下已有 `generatedItemAssets` 时不能因为图片完整性判断失败就覆盖为空数组。判断是否需要补读详情时只看 `imageViews[]``imageSrc/imageObjectKey`;背景、音乐、容器 UI 是附属运行态资产,不能单独证明物品素材已完整。
- 验证:执行 `npm run test -- src/components/match3d-result/Match3DResultView.test.tsx``npm run test -- src/components/match3d-runtime/Match3DRuntimeShell.test.tsx``npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx`,并检查历史草稿和公开 M3 作品的 Network 响应里 `generatedItemAssets[].modelSrc/modelObjectKey` - 验证:执行 `npm run test -- src/components/match3d-result/Match3DResultView.test.tsx``npm run test -- src/components/match3d-runtime/Match3DRuntimeShell.test.tsx``npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx`,并检查历史草稿和公开 M3 作品的 Network 响应里 `generatedItemAssets[].imageViews/imageSrc/imageObjectKey`
- 关联:`src/components/match3d-result/Match3DResultView.tsx``src/components/platform-entry/PlatformEntryFlowShellImpl.tsx``src/components/match3d-runtime/Match3DPhysicsBoard.tsx``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md` - 关联:`src/components/match3d-result/Match3DResultView.tsx``src/components/platform-entry/PlatformEntryFlowShellImpl.tsx``src/components/match3d-runtime/Match3DPhysicsBoard.tsx``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 抓大鹅结果页音频试听也要先换签
- 现象:抓大鹅草稿生成完成后,背景音乐已写在 `generatedItemAssets[0].backgroundMusic.audioSrc`,但 `素材配置 > 背景音乐` 或物品详情音效 `<audio>` 不能播放Network 可能请求裸 `/generated-match3d-assets/...mp3` 并返回 403。
- 原因:结果页试听控件和运行态一样运行在浏览器里,不能直接读取 generated 私有对象;只在运行态换签会造成“运行态可能有声,结果页不能预览”的割裂。
- 处理:结果页音频控件统一通过 `useResolvedAssetReadUrl` / `/api/assets/read-url` 取得签名 URL 后再传给 `<audio>`;换签失败时只显示“音频已绑定”,不要回退请求裸 generated path。
- 验证:`npm run test -- src/components/match3d-result/Match3DResultView.test.tsx` 覆盖背景音乐和点击音效试听使用签名 URL。
- 关联:`src/components/match3d-result/Match3DResultView.tsx``src/services/assetReadUrlService.ts``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 法律文档弹窗通过 portal 挂载时要显式带平台主题
- 现象:登录弹窗内点击协议链接打开法律文档时,弹窗可能继承不到 `platform-theme--light/dark` 变量,或者层级低于登录遮罩导致不可见。
- 原因:`UnifiedModal` 默认通过 portal 挂到 `document.body`,不再处于原页面的主题容器内;登录弹窗自身又使用较高 z-index。
- 处理:法律文档弹窗组件应支持传入 `platformTheme`overlay 上显式挂 `platform-theme platform-theme--*`,并使用高于登录遮罩的层级。法律内容必须作为独立面板打开,不要在当前个人页或登录面板下方内联展开。
- 验证:登录页协议链接、个人页法律入口均能打开可滚动 `LegalDocumentModal`,亮色 / 暗色主题文本和按钮可读。
## 生成页完成回调不能只依赖异步 React state
- 现象:抓大鹅或拼图点击生成后,进度页已经显示 100% / 生成完成,但没有自动进入试玩或结果页。
- 原因:完成回调用 `selectionStageRef.current` 判断用户是否仍在生成页;如果执行 compile 前只调用 `setSelectionStage('*-generating')`action 很快返回时 ref 仍可能是旧 stage。
- 处理:进入各玩法生成页时同步写 `selectionStageRef.current = '*-generating'`,再调用 `setSelectionStage('*-generating')`。这不是为渲染服务,而是给同一异步链路里的完成回调提供即时事实。
- 验证:`npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx` 覆盖抓大鹅和拼图生成后自动试玩 / 返回结果页。
- 关联:`src/components/platform-entry/PlatformEntryFlowShellImpl.tsx``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 微信支付回调验签不要用商户私钥
- 现象:微信小程序支付下单能返回 `prepay_id`,但真实支付通知验签失败,或者本地实现误把商户 API 私钥当作回调验签 key。
- 原因:商户私钥只用于商户请求微信支付和生成小程序 `paySign`;微信支付通知的 `Wechatpay-Signature` 需要使用微信支付平台公钥或平台证书公钥验签,并按通知头里的平台序列号匹配。
- 处理api-server 真实微信支付配置同时需要商户私钥与微信平台公钥:`WECHAT_PAY_PRIVATE_KEY_*` 用于签名,`WECHAT_PAY_PLATFORM_PUBLIC_KEY_*``WECHAT_PAY_PLATFORM_SERIAL_NO` 用于通知验签,`WECHAT_PAY_API_V3_KEY` 只用于解密通知 resource。支付成功后只通过通知里的 `out_trade_no` 确认本地 pending 订单,并保存 `transaction_id``profile_recharge_order.provider_transaction_id`
- 验证mock 通知测试只能覆盖本地回调推进;真实环境还需用微信支付平台公钥、真实通知头和 API v3 密钥验证签名与解密链路。
- 关联:`server-rs/crates/api-server/src/wechat_pay.rs``docs/technical/MY_TAB_ACCOUNT_RECHARGE_IMPLEMENTATION_2026-04-25.md`
## 抓大鹅历史草稿外部 Rodin GLB 链接必须转存后再试玩或发布
- 现象:草稿页预览模型失败并报 `GL_INVALID_ENUM: Invalid cap.`,或结果页能看到历史生成记录但试玩、发布和正式运行态仍显示默认积木。
- 原因:历史结果页手动 `重新生成` 会把 Hyper3D/Rodin 的外部 CDN 下载链接直接保存到 `generatedItemAssets[].modelSrc`,同时 `modelObjectKey` 为空。外部链接可能过期、跨域、返回 HTML 错误页或非 GLB 内容;前端预览和运行态不能把它当作稳定私有资产。
- 处理:该问题只适用于旧数据。结果页发现 `status = model_ready``modelSrc = https://...` 且无 `modelObjectKey` 时,可调用 `POST /api/creation/match3d/works/{profileId}/generated-models` 做一次性转存;新草稿和批量新增不得继续生成或依赖 GLB。若历史半修复数据同时保留外部 `modelSrc` 和平台 `modelObjectKey`,旧模型预览读取层优先用 `modelObjectKey`
- 验证:`npm run test -- src\components\match3d-result\Match3DResultView.test.tsx``npm run test -- src\components\match3d-runtime\Match3DRuntimeShell.test.tsx``npm run test -- src\components\rpg-entry\RpgEntryFlowShell.agent.interaction.test.tsx``cargo test -p api-server match3d_model_download --manifest-path server-rs\Cargo.toml`,并检查修复后响应中的 `generatedItemAssets[].modelObjectKey` 不为空。
- 关联:`server-rs/crates/api-server/src/match3d.rs``src/components/match3d-result/Match3DResultView.tsx``src/components/match3d-result/Match3DModelPreview.tsx``src/components/match3d-runtime/Match3DPhysicsBoard.tsx``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 抓大鹅难度配置的物品种类和消除次数必须分离
- 现象:历史草稿选择标准 / 硬核难度后,系统可能把 `clearCount` 当成局内物品种类数量,导致标准需要 12 种、硬核需要 20/21 种;素材不足时发布或试玩行为不一致。
- 原因:旧运行态把消除次数和类型数量绑在一起,结果页文案又同时展示“素材图片 / 局内类型”,导致前端、发布校验和 run start 口径不一致。
- 处理:统一使用 `物品种类` 口径:轻松 3、标准 9、进阶 15、硬核 21历史 `clearCount=20` 且难度为硬核的运行态按新硬核升为 21 组三消,避免 20 组却要求 21 种素材。发布前按 `image_ready` 且有 `imageViews[]``imageSrc/imageObjectKey` 的生成素材数量阻断不足难度;试玩不阻断,但通过 `itemTypeCountOverride` 自动降到已生成 2D 素材数量。重启从已有 run 快照反推实际物品种类,保持同一局重开不变。
- 验证:`npm run test -- src\components\match3d-result\Match3DResultView.test.tsx``cargo test -p module-match3d --manifest-path server-rs\Cargo.toml`,涉及发布 reducer 时补跑 `cargo test -p spacetime-module match3d --manifest-path server-rs\Cargo.toml`
- 关联:`src/components/match3d-result/Match3DResultView.tsx``src/services/match3d-runtime/match3dRuntimeClient.ts``server-rs/crates/module-match3d/src/application.rs``server-rs/crates/spacetime-module/src/match3d/mod.rs``docs/technical/MATCH3D_DRAFT_ASSET_GENERATION_PIPELINE_2026-05-10.md`
## 抓大鹅标签清洗不要把 `3D素材` 当编号剥掉 ## 抓大鹅标签清洗不要把 `3D素材` 当编号剥掉
- 现象AI 或兜底生成的 `3D素材` 标签在后端规范化后变成 `D素材` - 现象AI 或兜底生成的 `3D素材` 标签在后端规范化后变成 `D素材`

View File

@@ -104,10 +104,10 @@ Rust 加密摘要依赖口径:新代码不再引入 `sha1`OSS V4 签名、
`docs/technical/PRODUCT_NAMING_BAIMENG_RENAME_2026-05-01.md` 为准: `docs/technical/PRODUCT_NAMING_BAIMENG_RENAME_2026-05-01.md` 为准:
- 产品展示名:百梦 - 产品展示名:陶泥儿
- 消费单位: - 消费单位:
- 公开账号标识:百梦 - 公开账号标识:陶泥
- 创作侧称谓:百梦 - 创作侧称谓:陶泥儿
个人任务与埋点系统首版边界: 个人任务与埋点系统首版边界:
@@ -117,7 +117,7 @@ Rust 加密摘要依赖口径:新代码不再引入 `sha1`OSS V4 签名、
- 任务进度写入 `profile_task_progress` - 任务进度写入 `profile_task_progress`
- 领奖记录写入 `profile_task_reward_claim` - 领奖记录写入 `profile_task_reward_claim`
- 钱包流水写入 `profile_wallet_ledger` - 钱包流水写入 `profile_wallet_ledger`
- “星光”奖励复用现有“点”钱包,不新增第二种货币 - “星光”奖励复用现有“点”钱包,不新增第二种货币
- 个人任务 scope 首版仅支持 `user` - 个人任务 scope 首版仅支持 `user`
## 关键文档入口 ## 关键文档入口

View File

@@ -1,23 +1,23 @@
--- ---
name: genarrative-admin-backoffice name: genarrative-admin-backoffice
short_description: 在 Genarrative/百梦后台新增或修改管理页、后台只读/写接口、导出能力时使用。 short_description: 在 Genarrative/陶泥儿后台新增或修改管理页、后台只读/写接口、导出能力时使用。
description: 在 Genarrative/百梦后台新增或修改管理页、后台 BFF 接口、shared-contracts/admin DTO、admin-web 路由导航、Excel/表格导出与验证发布时使用。 description: 在 Genarrative/陶泥儿后台新增或修改管理页、后台 BFF 接口、shared-contracts/admin DTO、admin-web 路由导航、Excel/表格导出与验证发布时使用。
version: 1.0.0 version: 1.0.0
author: Hermes Agent author: Hermes Agent
license: MIT license: MIT
metadata: metadata:
hermes: hermes:
tags: [Genarrative, 百梦后台, admin-web, 后台接口, Excel导出, Rust, Axum, SpacetimeDB] tags: [Genarrative, 陶泥儿后台, admin-web, 后台接口, Excel导出, Rust, Axum, SpacetimeDB]
related_skills: [genarrative-play-type-integration] related_skills: [genarrative-play-type-integration]
--- ---
# Genarrative / 百梦后台管理功能接入流程 # Genarrative / 陶泥儿后台管理功能接入流程
用于在 Genarrative 项目中新增或修改百梦后台管理端能力,包括后台页面、后台 API、管理端 DTO、导航路由、表格明细、导出、鉴权与验证。 用于在 Genarrative 项目中新增或修改陶泥儿后台管理端能力,包括后台页面、后台 API、管理端 DTO、导航路由、表格明细、导出、鉴权与验证。
## 适用场景 ## 适用场景
- 新增百梦后台页面或导航项,例如“埋点数据”“任务配置”“邀请码”。 - 新增陶泥儿后台页面或导航项,例如“埋点数据”“任务配置”“邀请码”。
- 新增 `/admin/api/*` 接口。 - 新增 `/admin/api/*` 接口。
- 修改 `apps/admin-web` 的后台页面、API client、路由、Shell 导航。 - 修改 `apps/admin-web` 的后台页面、API client、路由、Shell 导航。
- 在后台展示 SpacetimeDB 表明细或统计数据。 - 在后台展示 SpacetimeDB 表明细或统计数据。

View File

@@ -2,7 +2,7 @@
## 背景 ## 背景
本次在 Genarrative/百梦后台新增“埋点数据”页: 本次在 Genarrative/陶泥儿后台新增“埋点数据”页:
- 后端新增 `GET /admin/api/tracking/events` - 后端新增 `GET /admin/api/tracking/events`
- shared-contracts 新增 admin tracking query/list/entry DTO。 - shared-contracts 新增 admin tracking query/list/entry DTO。

View File

@@ -0,0 +1,108 @@
# api-server 能力模块化与生成资产 Adapter 完整收口计划
状态:待执行
## Summary
目标是把 `api-server` 从“超大 `app.rs` + 多个超大 handler 文件 + 多处生成资产重复链路”收成可长期维护的能力 Module 结构。
本计划完整覆盖:路由能力模块化、生成图片资产 Adapter、复杂媒体链路扩展、大 handler 瘦身、文档与验收。全程不改变 HTTP contract、DTO、SpacetimeDB schema、前端行为和计费语义除非某阶段文档先明确提出并单独批准。
## 文档交付
先新增一个总纲,再按阶段新增单独执行文档:
- 总纲:`docs/technical/【后端架构】api-server能力模块化与生成资产Adapter总纲-2026-05-14.md`
- 阶段 1`docs/technical/【后端架构】api-server路由能力模块化执行计划-2026-05-14.md`
- 阶段 2`docs/technical/【后端架构】生成图片资产Adapter收口执行计划-2026-05-14.md`
- 阶段 3`docs/technical/【后端架构】复杂媒体资产链路Adapter扩展计划-2026-05-14.md`
- 阶段 4`docs/technical/【后端架构】api-server大Handler瘦身执行计划-2026-05-14.md`
- 同步更新 `server-rs/crates/api-server/README.md``docs/technical/README.md`、本 TODO 文档。
## 阶段 0基线盘点与总纲冻结
- 盘点 `app.rs` 当前全部 route`admin/auth/assets/profile/creation/runtime/story/platform/internal` 分类形成 route inventory。
- 盘点 Big Fish、Square Hole、Custom World、Puzzle、Match3D、Visual Novel、音频、视频、GLB 的生成资产链路,标出 provider、下载方式、OSS prefix、asset kind、entity binding、计费位置、降级行为。
- 在总纲文档中冻结边界:`api-server` 只做 HTTP/SSE/BFF、鉴权、DTO 映射、平台服务编排;领域规则仍归 `module-*`SpacetimeDB 真相仍归 `spacetime-module`
退出条件:总纲和 inventory 能指导后续编码,不再只是一段方向描述。
## 阶段 1路由能力模块化完整收口
- 新增 `server-rs/crates/api-server/src/modules/`,每个能力 Module 暴露 `router(state) -> Router<AppState>`
- 第一批迁移低风险路由:`admin``auth``assets``profile``internal``health`
- 第二批迁移平台编排路由:`ai_tasks``llm``speech``wechat``creative_agent``visual_novel`、通用 audio。
- 第三批迁移玩法路由:`big_fish``square_hole``puzzle``match3d``custom_world``story`、runtime save/settings/chat/inventory。
- `app.rs` 最终只保留全局 middleware、TraceLayer、request context、tracking middleware、`.merge(modules::*::router(...))` 和少量顶层 glue。
- handler 实现第一阶段可以继续留在原文件;本阶段只改变路由装配位置,不混入业务重构。
验收route inventory 中所有原 route 仍存在;旧明确下线 route 继续 404`cargo test -p api-server app --manifest-path server-rs/Cargo.toml` 或等价 route 回归通过。
## 阶段 2稳定单图生成资产 Adapter 收口
- 新增 `modules/assets/generated_image_assets` 内部 ModuleInterface 覆盖“provider 生成 -> 下载/base64 解码 -> MIME/extension 归一 -> OSS private upload -> HEAD -> asset_object confirm -> entity binding”。
- Adapter 输入包含 provider、prompt、negative prompt、size、reference images、OSS prefix/path/file name、asset kind、entity kind/id、slot、owner/profile/source_job_id、metadata、可选透明背景后处理。
- Adapter 输出包含 `legacy_public_path``object_key``asset_object_id``mime_type``extension``task_id``actual_prompt`
- 首批迁移:
- Big Fish 正式图片:主图、动作图、舞台背景。
- Square Hole 图片:保留生成成功但入库失败时回退 Data URL。
- Custom World 场景图、自动草稿场景图、生成封面图。
- `asset_billing.rs` 仍由调用方显式包裹Adapter 不扣费、不退款、不读钱包。
验收:三类调用方都经过同一 Adapter删除旧重复 persist 函数后行为不变Big Fish、Square Hole、Custom World 定向测试通过。
## 阶段 3复杂媒体资产链路扩展
- 扩展 Adapter但不把玩法图像处理规则塞进公共 Interface。
- Puzzle
- 收口普通 generations、edits/multipart 生成结果的下载、OSS、asset object、binding。
- 拼图关卡 JSON 更新、参考图策略、UI 背景落位仍留在 Puzzle 编排层。
- Match3D
- APIMart material sheet、VectorEngine 背景/容器/封面生成接入统一入库能力。
- 5x5 切图、绿幕透明化、格内校准、批量新增补齐规则仍留在 Match3D 专属处理器。
- 音频:
- 评估是否抽 `generated_media_assets`,但背景音乐、点击音效的计费和落位语义不与图片 Adapter 混用。
- GLB/视频:
- 仅历史转存链路复用“OSS + asset_object + binding”底层持久化能力不恢复新草稿 GLB 生产。
验收Puzzle 与 Match3D 的 generated 私有资产仍通过 `/api/assets/read-url` 换签读取Match3D 不回退 Rodin/GLB音频试听和运行态仍可播放。
## 阶段 4超大 handler 能力内瘦身
- 在路由已模块化、资产 Adapter 已稳定后,再拆大文件,避免同时改 route 和业务实现。
-`match3d.rs``puzzle.rs``custom_world.rs``custom_world_ai.rs``big_fish.rs``square_hole.rs` 分别按能力拆:
- `router.rs` 只挂路由。
- `handlers.rs` 只做 Axum extract、鉴权、request/response。
- `application.rs` 做 api-server 层编排。
- `assets.rs` 只放玩法专属生成资产策略。
- `mapper.rs` 只做 DTO/record 映射。
- `errors.rs` 只做该能力错误映射。
- 不把领域规则留在 handler发现领域规则时只登记迁出候选不在本阶段直接扩大到 `module-*` 重构。
验收:每个原超大文件显著缩小;新文件按能力可读;定向玩法测试和全量 `api-server` 测试通过。
## 阶段 5清理、文档和最终验收
- 删除旧重复 helper、过时注释和已迁移的私有函数。
- 更新 `api-server` README目录规则、Router 暴露规则、Adapter 边界、禁止事项。
- 更新 `.hermes/shared-memory` 中长期有效的架构约定和排障经验。
- 最终验收命令:
- `cargo check -p api-server --manifest-path server-rs/Cargo.toml`
- `cargo test -p api-server --manifest-path server-rs/Cargo.toml`
- `npm run check:server-rs-ddd`
- `npm run check:encoding`
- `git diff --check`
- `npm run api-server` 后检查 `/healthz`
- 禁止使用 `api-server:maincloud` 作为本轮 smoke。
## Public Interfaces
- HTTP route、DTO、error envelope、SpacetimeDB schema、前端调用方式默认不变。
- 新增的都是 `api-server` 内部 Rust Interface不进入 `shared-contracts`
- 若后续任何阶段发现必须改 contract先更新对应阶段文档和 G1 route/contract 矩阵,再单独实施。
## Assumptions
- 本计划目标是完整收口,不是只完成第一阶段。
- 可以分阶段提交,但每个阶段都必须有文档、测试和明确退出条件。
- `generated_image_assets` 首版必须至少被三个真实调用方使用,否则不算形成有效 Module。

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>百梦后台</title> <title>陶泥儿后台</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

View File

@@ -50,7 +50,7 @@ export function AdminShell({
<ShieldCheck size={20} aria-hidden="true" /> <ShieldCheck size={20} aria-hidden="true" />
</div> </div>
<div> <div>
<strong></strong> <strong></strong>
<span>Admin</span> <span>Admin</span>
</div> </div>
</div> </div>

View File

@@ -86,7 +86,7 @@ export const adminTrackingEventDefinitions: AdminTrackingEventDefinition[] = [
key: 'wallet_ledger_view', key: 'wallet_ledger_view',
title: '钱包流水查看', title: '钱包流水查看',
scopeKind: 'user', scopeKind: 'user',
remark: '读取点钱包流水成功后记录。', remark: '读取点钱包流水成功后记录。',
}, },
{ {
key: 'recharge_center_view', key: 'recharge_center_view',

View File

@@ -742,9 +742,9 @@ const databaseTableColumnLabelMap: Record<string, string> = {
theme_tags_json: '主题标签JSON', theme_tags_json: '主题标签JSON',
cover_image_src: '封面图', cover_image_src: '封面图',
cover_asset_id: '封面资产ID', cover_asset_id: '封面资产ID',
public_user_code: '百梦号', public_user_code: '陶泥号',
public_work_code: '公开作品号', public_work_code: '公开作品号',
author_public_user_code: '作者百梦号', author_public_user_code: '作者陶泥号',
author_display_name: '作者昵称', author_display_name: '作者昵称',
display_name: '显示名', display_name: '显示名',
avatar_url: '头像地址', avatar_url: '头像地址',
@@ -874,9 +874,9 @@ const databaseTableColumnDescriptionMap: Record<string, string> = {
theme_tags_json: '主题标签列表 JSON', theme_tags_json: '主题标签列表 JSON',
cover_image_src: '封面图片地址或平台资产引用', cover_image_src: '封面图片地址或平台资产引用',
cover_asset_id: '封面对应的平台资产 ID', cover_asset_id: '封面对应的平台资产 ID',
public_user_code: '用户对外展示的百梦号', public_user_code: '用户对外展示的陶泥号',
public_work_code: '作品公开后对外展示的作品号', public_work_code: '作品公开后对外展示的作品号',
author_public_user_code: '作者对外展示的百梦号', author_public_user_code: '作者对外展示的陶泥号',
author_display_name: '作者展示昵称', author_display_name: '作者展示昵称',
display_name: '用户展示名称', display_name: '用户展示名称',
avatar_url: '用户头像地址', avatar_url: '用户头像地址',

View File

@@ -39,7 +39,7 @@ export function AdminLoginPage({notice, onLogin}: AdminLoginPageProps) {
<ShieldCheck size={26} aria-hidden="true" /> <ShieldCheck size={26} aria-hidden="true" />
</div> </div>
<div> <div>
<h1></h1> <h1></h1>
<span>Admin Console</span> <span>Admin Console</span>
</div> </div>
</div> </div>

View File

@@ -253,7 +253,7 @@ export function AdminRedeemCodePage({
/> />
</label> </label>
<label className="admin-field"> <label className="admin-field">
<span></span> <span></span>
<textarea <textarea
rows={6} rows={6}
value={allowedPublicUserCodes} value={allowedPublicUserCodes}

View File

@@ -373,7 +373,7 @@ export function AdminTaskConfigPage({
/> />
</label> </label>
<label className="admin-field"> <label className="admin-field">
<span></span> <span></span>
<input <input
min={1} min={1}
step={1} step={1}

View File

@@ -37,6 +37,7 @@ GENARRATIVE_CREATION_AGENT_LLM_WEB_SEARCH_ENABLED=false
APIMART_BASE_URL= APIMART_BASE_URL=
APIMART_API_KEY= APIMART_API_KEY=
APIMART_IMAGE_REQUEST_TIMEOUT_MS=180000
VECTOR_ENGINE_BASE_URL=https://api.vectorengine.ai VECTOR_ENGINE_BASE_URL=https://api.vectorengine.ai
VECTOR_ENGINE_API_KEY= VECTOR_ENGINE_API_KEY=

34
deploy/nginx/README.md Normal file
View File

@@ -0,0 +1,34 @@
# Genarrative Nginx compression policy
本配置片段由 `scripts/jenkins-server-provision.sh` 在安装 Nginx 站点配置时展开。
## gzip
- `deploy/nginx/genarrative.conf``deploy/nginx/genarrative-dev-http.conf` 默认开启 gzip。
- 覆盖 `application/json`,用于降低 `/api/runtime/*/gallery` 这类 JSON 列表接口的公网带宽占用。
- 当前推荐等级为 `gzip_comp_level 5`,兼顾 2C/2G 服务器 CPU 与压缩收益。
## Brotli
- Brotli 只在目标服务器 Nginx 接受 brotli 指令时开启。
- Provision 脚本通过临时配置执行 `nginx -t` 做能力探测;探测配置会先 `include /etc/nginx/modules-enabled/*.conf`,避免 Ubuntu 动态模块已安装但测试配置未加载模块导致误判。可用时把模板中的 `# __GENARRATIVE_BROTLI_DIRECTIVES__` 替换为 brotli 指令,不可用时保留注释说明。
- 不要直接在静态模板里无条件写 `brotli on;`,否则没有 brotli 模块的服务器会 `nginx -t` 失败并回滚。
- 不要用 `nginx -V | grep brotli` 判断 brotli 是否可用Ubuntu apt 安装的 brotli 是动态模块,可能只出现在 `nginx -T``load_module` 配置里。
## 验证
```bash
curl -sSI -H 'Accept-Encoding: gzip' \
http://<host>/api/runtime/puzzle/gallery \
| grep -iE 'content-encoding|vary|content-type|content-length'
curl -sSI -H 'Accept-Encoding: br' \
http://<host>/api/runtime/puzzle/gallery \
| grep -iE 'content-encoding|vary|content-type|content-length'
```
预期:
- gzip 可用时返回 `Content-Encoding: gzip`
- br 可用时返回 `Content-Encoding: br`
- 响应头应包含 `Vary: Accept-Encoding`

View File

@@ -5,6 +5,23 @@ server {
listen 80; listen 80;
server_name genarrative.example.com; server_name genarrative.example.com;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
application/xml+rss
image/svg+xml;
# __GENARRATIVE_BROTLI_DIRECTIVES__
root /srv/genarrative/web; root /srv/genarrative/web;
index index.html; index index.html;

View File

@@ -16,6 +16,23 @@ server {
listen 443 ssl http2; listen 443 ssl http2;
server_name genarrative.example.com; server_name genarrative.example.com;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
application/xml+rss
image/svg+xml;
# __GENARRATIVE_BROTLI_DIRECTIVES__
ssl_certificate /etc/letsencrypt/live/genarrative.example.com/fullchain.pem; ssl_certificate /etc/letsencrypt/live/genarrative.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/genarrative.example.com/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/genarrative.example.com/privkey.pem;

View File

@@ -13,7 +13,7 @@
重点补充RPG 创作与运行时脚本职责地图见 [RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md](./reference/RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md)。 重点补充RPG 创作与运行时脚本职责地图见 [RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md](./reference/RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md)。
- [埋点查询](./tracking/README.md):埋点原始事件与聚合投影的本地 SQL 查询。 - [埋点查询](./tracking/README.md):埋点原始事件与聚合投影的本地 SQL 查询。
- [运营查询](./operations/README.md):任务、领奖、钱包对账等后台核查查询。 - [运营查询](./operations/README.md):任务、领奖、钱包对账等后台核查查询。
- [PRD](./prd/README.md):产品需求与阶段计划;参考 MOKU / 幕间类 AI 文游的百梦 `text-game` 模板口径见 [AI_NATIVE_TEXT_GAME_TEMPLATE_MOKU_REFERENCE_PRD_2026-05-05.md](./prd/AI_NATIVE_TEXT_GAME_TEMPLATE_MOKU_REFERENCE_PRD_2026-05-05.md),视觉小说模板 TXT 玩法平台化接入口径见 [AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.md](./prd/AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.md),创意互动内容 Agent Phase 1 的 LangChain-Rust PoC、拼图闭环和并行任务拆分见 [CREATIVE_INTERACTIVE_AGENT_PHASE1_LANGCHAIN_RUST_PUZZLE_LOOP_PRD_2026-05-05.md](./prd/CREATIVE_INTERACTIVE_AGENT_PHASE1_LANGCHAIN_RUST_PUZZLE_LOOP_PRD_2026-05-05.md),幸存者类模板闭环见 [AI_NATIVE_SURVIVOR_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-05.md](./prd/AI_NATIVE_SURVIVOR_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-05.md),后台管理独立前端工程见 [ADMIN_WEB_CONSOLE_PRD_2026-04-30.md](./prd/ADMIN_WEB_CONSOLE_PRD_2026-04-30.md),新增 RPG 开场动画方案见 [AI_NATIVE_RPG_OPENING_ANIMATION_PRD_2026-04-25.md](./prd/AI_NATIVE_RPG_OPENING_ANIMATION_PRD_2026-04-25.md),新增抓大鹅 Match3D 玩法方案见 [AI_NATIVE_MATCH3D_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-30.md](./prd/AI_NATIVE_MATCH3D_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-30.md),方洞挑战创作、发布与试玩闭环见 [AI_NATIVE_SQUARE_HOLE_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-04.md](./prd/AI_NATIVE_SQUARE_HOLE_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-04.md)。 - [PRD](./prd/README.md):产品需求与阶段计划;参考 MOKU / 幕间类 AI 文游的陶泥儿 `text-game` 模板口径见 [AI_NATIVE_TEXT_GAME_TEMPLATE_MOKU_REFERENCE_PRD_2026-05-05.md](./prd/AI_NATIVE_TEXT_GAME_TEMPLATE_MOKU_REFERENCE_PRD_2026-05-05.md),视觉小说模板 TXT 玩法平台化接入口径见 [AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.md](./prd/AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.md),创意互动内容 Agent Phase 1 的 LangChain-Rust PoC、拼图闭环和并行任务拆分见 [CREATIVE_INTERACTIVE_AGENT_PHASE1_LANGCHAIN_RUST_PUZZLE_LOOP_PRD_2026-05-05.md](./prd/CREATIVE_INTERACTIVE_AGENT_PHASE1_LANGCHAIN_RUST_PUZZLE_LOOP_PRD_2026-05-05.md),幸存者类模板闭环见 [AI_NATIVE_SURVIVOR_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-05.md](./prd/AI_NATIVE_SURVIVOR_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-05.md),后台管理独立前端工程见 [ADMIN_WEB_CONSOLE_PRD_2026-04-30.md](./prd/ADMIN_WEB_CONSOLE_PRD_2026-04-30.md),新增 RPG 开场动画方案见 [AI_NATIVE_RPG_OPENING_ANIMATION_PRD_2026-04-25.md](./prd/AI_NATIVE_RPG_OPENING_ANIMATION_PRD_2026-04-25.md),新增抓大鹅 Match3D 玩法方案见 [AI_NATIVE_MATCH3D_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-30.md](./prd/AI_NATIVE_MATCH3D_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-30.md),方洞挑战创作、发布与试玩闭环见 [AI_NATIVE_SQUARE_HOLE_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-04.md](./prd/AI_NATIVE_SQUARE_HOLE_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-04.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)。

View File

@@ -2,7 +2,7 @@
Issues and PRDs for this repo live as issues in the self-hosted Gitea remote: Issues and PRDs for this repo live as issues in the self-hosted Gitea remote:
- Remote: `http://82.157.175.59:3000/GenarrativeAI/Genarrative.git` - Remote: `https://git.genarrative.world/GenarrativeAI/Genarrative.git`
- Tracker type: Gitea Issues - Tracker type: Gitea Issues
## Conventions ## Conventions

View File

@@ -6,7 +6,7 @@
当前自定义世界创作工具已经有了比较强的生成骨架、锚点结构和结果编辑能力,但整体仍处在一个很明显的“半收口状态”: 当前自定义世界创作工具已经有了比较强的生成骨架、锚点结构和结果编辑能力,但整体仍处在一个很明显的“半收口状态”:
**设计目标已经走到“百梦主工作台”,数据结构已经支持“锚点化输入”,但实际体验仍然更像“大文本生成器 + 大型结果总表编辑器”。** **设计目标已经走到“陶泥儿主工作台”,数据结构已经支持“锚点化输入”,但实际体验仍然更像“大文本生成器 + 大型结果总表编辑器”。**
如果用一句话概括当前问题,就是: 如果用一句话概括当前问题,就是:
@@ -61,7 +61,7 @@
- 标志性要素 - 标志性要素
- 禁止事项 - 禁止事项
但实际入口 `src/components/SelectionCustomizationModals.tsx` 里,百梦主弹窗仍然基本只有: 但实际入口 `src/components/SelectionCustomizationModals.tsx` 里,陶泥儿主弹窗仍然基本只有:
- 生成模式 - 生成模式
- 一块大 textarea - 一块大 textarea
@@ -82,7 +82,7 @@
--- ---
## 2.2 澄清机制已经存在,但没有真正服务百梦 ## 2.2 澄清机制已经存在,但没有真正服务陶泥儿
`server-node/src/services/customWorldSessionStore.ts` 已经支持: `server-node/src/services/customWorldSessionStore.ts` 已经支持:
@@ -101,7 +101,7 @@
这意味着: 这意味着:
**系统表面上已经有“先澄清再生成”的能力,但实际体验里,百梦主并没有真正参与这一步。** **系统表面上已经有“先澄清再生成”的能力,但实际体验里,陶泥儿主并没有真正参与这一步。**
结果就是: 结果就是:
@@ -113,7 +113,7 @@
- 把 session question 真正接到前端,作为生成前的二次确认步骤。 - 把 session question 真正接到前端,作为生成前的二次确认步骤。
- 每次只问 `1~3` 个最关键问题,不要把它做成问卷。 - 每次只问 `1~3` 个最关键问题,不要把它做成问卷。
- 支持“一键使用系统建议”,但必须让百梦主可见,而不是静默自动填充。 - 支持“一键使用系统建议”,但必须让陶泥儿主可见,而不是静默自动填充。
- 把回答结果回写到 `creatorIntent`,而不是只作为一次性会话答案。 - 把回答结果回写到 `creatorIntent`,而不是只作为一次性会话答案。
--- ---
@@ -175,7 +175,7 @@
这会带来三层问题: 这会带来三层问题:
1. 百梦主负担过重 1. 陶泥儿主负担过重
- 很多字段属于“系统编译层”,不属于“创作决策层”。 - 很多字段属于“系统编译层”,不属于“创作决策层”。
2. 移动端负担过重 2. 移动端负担过重
@@ -240,7 +240,7 @@
--- ---
## 2.6 快速模式还不够“快”,生成页也还不够“百梦主视角” ## 2.6 快速模式还不够“快”,生成页也还不够“陶泥儿主视角”
当前快速模式的主要区别,是把数量降成: 当前快速模式的主要区别,是把数量降成:
@@ -269,7 +269,7 @@
- 计时 - 计时
- 模型阶段 - 模型阶段
而不是百梦主真正关心的: 而不是陶泥儿主真正关心的:
- 关键角色有没有成型 - 关键角色有没有成型
- 核心冲突有没有稳定 - 核心冲突有没有稳定
@@ -281,7 +281,7 @@
- 快速模式改成真正的“关键锚点预览模式”: - 快速模式改成真正的“关键锚点预览模式”:
- 先只生成关键角色、关键地点、核心冲突摘要 - 先只生成关键角色、关键地点、核心冲突摘要
- 暂不补全所有长尾档案 - 暂不补全所有长尾档案
- 生成页改成“百梦主视角进度”: - 生成页改成“陶泥儿主视角进度”:
- 世界灵魂已确定 - 世界灵魂已确定
- 关键角色已成型 - 关键角色已成型
- 关键地点已落地 - 关键地点已落地
@@ -391,16 +391,16 @@
### P0先修主链路闭环 ### P0先修主链路闭环
- 补卡片化输入入口,至少把关键锚点输入真正开放出来。 - 补卡片化输入入口,至少把关键锚点输入真正开放出来。
- 把澄清问题正式接入百梦主流程,不再静默自动兜底。 - 把澄清问题正式接入陶泥儿主流程,不再静默自动兜底。
- 修正“新建完成后直接回世界列表”的流程,生成后默认进入结果工作台。 - 修正“新建完成后直接回世界列表”的流程,生成后默认进入结果工作台。
- 统一锁定与局部重生成规则,先让“百梦主不怕重生成”成立。 - 统一锁定与局部重生成规则,先让“陶泥儿主不怕重生成”成立。
### P1再降低工作台负担 ### P1再降低工作台负担
- 结果页默认只展示高杠杆编辑。 - 结果页默认只展示高杠杆编辑。
- 低杠杆字段进入高级模式。 - 低杠杆字段进入高级模式。
- 快速模式改成真正的关键对象预览模式。 - 快速模式改成真正的关键对象预览模式。
- 生成页改成百梦主视角进度,而不是模型批次视角。 - 生成页改成陶泥儿主视角进度,而不是模型批次视角。
### P2最后做架构收口与去模板化 ### P2最后做架构收口与去模板化
@@ -441,4 +441,4 @@
当前自定义世界创作工具最需要的,不是再继续补更多字段或更多生成步骤,而是: 当前自定义世界创作工具最需要的,不是再继续补更多字段或更多生成步骤,而是:
**把“百梦主先决定灵魂锚点,系统再稳定展开世界”这条主逻辑真正落到 UI、流程和后端边界上。** **把“陶泥儿主先决定灵魂锚点,系统再稳定展开世界”这条主逻辑真正落到 UI、流程和后端边界上。**

View File

@@ -1,15 +1,15 @@
# 百梦线下展会易拉宝设计记录 2026-05-07 # 陶泥儿线下展会易拉宝设计记录 2026-05-07
## 1. 目标 ## 1. 目标
百梦线下展会制作一张纵向易拉宝广告展板,用于在展位现场快速传达: 陶泥儿线下展会制作一张纵向易拉宝广告展板,用于在展位现场快速传达:
1. 产品名称:百梦 1. 产品名称:陶泥儿
2. 产品愿景:百梦AI团队致力于打造AI互动内容UGC平台。 2. 产品愿景:陶泥儿AI团队致力于打造AI互动内容UGC平台。
3. 产品slogan不用代码不用美术10分钟把脑洞变成有趣的体验。 3. 产品slogan不用代码不用美术10分钟把脑洞变成有趣的体验。
4. 产品特点:低门槛创作、高完成度作品、玩过后可改造并发布。 4. 产品特点:低门槛创作、高完成度作品、玩过后可改造并发布。
5. 关键技术Harness Engineering、多Agent调度、AI创作工具、AI原生游戏框架。 5. 关键技术Harness Engineering、多Agent调度、AI创作工具、AI原生游戏框架。
6. 产品心智:想玩但找不到、玩到不满意、平台外体验不满意时,都可以来百梦做成自己满意的。 6. 产品心智:想玩但找不到、玩到不满意、平台外体验不满意时,都可以来陶泥儿做成自己满意的。
## 2. 视觉方向 ## 2. 视觉方向
@@ -27,7 +27,7 @@
第一层:品牌识别 第一层:品牌识别
```text ```text
百梦 陶泥儿
10分钟做自己的互动内容 10分钟做自己的互动内容
``` ```
@@ -57,10 +57,10 @@
第四层:产品心智与关键技术 第四层:产品心智与关键技术
```text ```text
当用户找不到想玩的游戏 -> 来百梦做给自己玩 当用户找不到想玩的游戏 -> 来陶泥儿做给自己玩
当用户玩到了不好玩的游戏 -> 快速改成自己喜欢玩的 当用户玩到了不好玩的游戏 -> 快速改成自己喜欢玩的
当用户在平台外玩到了不满意的游戏 -> 来百梦做成自己满意的 当用户在平台外玩到了不满意的游戏 -> 来陶泥儿做成自己满意的
什么游戏最好玩? -> 来百梦玩自己做的游戏最好玩 什么游戏最好玩? -> 来陶泥儿玩自己做的游戏最好玩
``` ```
关键技术压缩为: 关键技术压缩为:
@@ -82,7 +82,7 @@ AI原生游戏框架
```text ```text
model: gpt-image-2 model: gpt-image-2
size: 1536x3840 size: 1536x3840
reference image: 百梦气泡共创logo方向图 reference image: 陶泥儿气泡共创logo方向图
output: output/imagegen/baimeng-expo-rollup/baimeng-rollup-background-gpt-image-2.png output: output/imagegen/baimeng-expo-rollup/baimeng-rollup-background-gpt-image-2.png
``` ```
@@ -108,3 +108,42 @@ output/imagegen/baimeng-expo-rollup/baimeng-rollup-final-cn-preview.png
2. 若需要放二维码,应放在底部独立留白区,不遮挡产品心智和关键技术段。 2. 若需要放二维码,应放在底部独立留白区,不遮挡产品心智和关键技术段。
3. 若展会现场观众偏投资人或B端合作方可以把“产品心智”段压缩放大“关键技术”与平台愿景。 3. 若展会现场观众偏投资人或B端合作方可以把“产品心智”段压缩放大“关键技术”与平台愿景。
4. 若观众偏玩家或普通创作者可以把“关键技术”段压缩放大“10分钟创作、玩过就改、发布分享”的闭环。 4. 若观众偏玩家或普通创作者可以把“关键技术”段压缩放大“10分钟创作、玩过就改、发布分享”的闭环。
## 6. 公司招聘版 2026-05-11
2026-05-11 根据线下招聘场景,将海报方向从“纯产品宣传”调整为“公司 + 产品 + 岗位”的整体宣传。
新版定位:
```text
北京亓盒网络科技有限公司
岗位名称AI 原生游戏产品/内容实习生
行业方向AI 原生游戏 × UGC 内容创作 × 互动叙事
产品:陶泥儿 AI互动内容创作平台
```
新版保留陶泥儿气泡色彩、轻盈白底和创作流动感但新增校园实验室、AI 游戏创作、作品卡、产品测试与内容设计氛围。版面结构调整为:
1. 顶部:公司名、岗位名、行业方向与招聘主标题。
2. 中上:陶泥儿产品主张与三枚产品能力标签。
3. 中部:按 `游玩 -> 改造 -> 创作` 顺序展示产品体验闭环。
4. 中下:介绍“我们正在做的事「陶泥儿」”。
5. 下部:实习生参与内容、加分项、团队背景和联系方式。
6. 底部:预留两个方形二维码占位,收尾文案为 `陶泥儿 | 让每个人都能做自己的游戏`
新版使用当前仓库 `VectorEngine gpt-image-2-all` 路径生成底图:
```text
model: gpt-image-2-all
size: 1536x3840
reference image 1: 用户提供的上一版海报截图
reference image 2: 陶泥儿气泡共创logo方向图
output: output/imagegen/baimeng-recruitment-rollup/baimeng-recruitment-rollup-background-gpt-image-2-all.png
```
最终输出:
```text
output/imagegen/baimeng-recruitment-rollup/baimeng-recruitment-rollup-final-cn.png
output/imagegen/baimeng-recruitment-rollup/baimeng-recruitment-rollup-final-cn-preview.png
```

View File

@@ -1,8 +1,8 @@
# 百梦 logo gpt-image-2 概念方案 2026-05-05 # 陶泥儿 logo gpt-image-2 概念方案 2026-05-05
## 1. 产品气质提炼 ## 1. 产品气质提炼
当前产品对外名为“百梦”,核心不是单一 RPG 玩法,而是面向互动叙事、世界生成和运行时演出的 AI 原生创作平台。 当前产品对外名为“陶泥儿”,核心不是单一 RPG 玩法,而是面向互动叙事、世界生成和运行时演出的 AI 原生创作平台。
本次 logo 概念围绕以下关键词设计: 本次 logo 概念围绕以下关键词设计:
@@ -16,7 +16,7 @@
视觉方向: 视觉方向:
- 用一个打开的门 / 星门作为主体,门内有多条细线向外延展,代表百梦主从一个灵感入口进入多个世界。 - 用一个打开的门 / 星门作为主体,门内有多条细线向外延展,代表陶泥儿主从一个灵感入口进入多个世界。
- 负形中弱化出“百”的结构,不强行写字,方便后续做 App icon、favicon 和小尺寸导航标。 - 负形中弱化出“百”的结构,不强行写字,方便后续做 App icon、favicon 和小尺寸导航标。
- 色彩以暖白、珊瑚粉、少量紫蓝和深墨色组成,贴近平台亮色主题,同时保留梦境和 AI 的科技感。 - 色彩以暖白、珊瑚粉、少量紫蓝和深墨色组成,贴近平台亮色主题,同时保留梦境和 AI 的科技感。
@@ -28,7 +28,7 @@
设计含义: 设计含义:
“梦门”代表创作入口,“星轨”代表剧情线程、角色关系和世界分支。它强调百梦是让创作者开启世界的工具,而不是只播放固定剧情的游戏。 “梦门”代表创作入口,“星轨”代表剧情线程、角色关系和世界分支。它强调陶泥儿是让创作者开启世界的工具,而不是只播放固定剧情的游戏。
## 3. 方案 B叙事图谱 ## 3. 方案 B叙事图谱
@@ -36,7 +36,7 @@
- 用节点、弧线和轻微书页轮廓组成一个稳定的圆形标志。 - 用节点、弧线和轻微书页轮廓组成一个稳定的圆形标志。
- 图谱整体形成近似“百”的秩序感,避免复杂到小尺寸失真。 - 图谱整体形成近似“百”的秩序感,避免复杂到小尺寸失真。
- 色彩以深墨、湖青、点金和珊瑚色组合,体现规则边界与创作活力并存。 - 色彩以深墨、湖青、点金和珊瑚色组合,体现规则边界与创作活力并存。
适合场景: 适合场景:
@@ -48,13 +48,13 @@
这个方向更强调“世界不是一段文本,而是一张可控的叙事图谱”。节点是角色、地点、物件和任务,弧线是关系、暗线与回响。 这个方向更强调“世界不是一段文本,而是一张可控的叙事图谱”。节点是角色、地点、物件和任务,弧线是关系、暗线与回响。
## 4. 方案 C点梦织 ## 4. 方案 C点梦织
视觉方向: 视觉方向:
- 多个点汇聚成柔和的“B / 百”抽象符号,中心像一枚被点亮的种子。 - 多个点汇聚成柔和的“B / 百”抽象符号,中心像一枚被点亮的种子。
- 线条更轻,图形更偏平台化和消费级,不做重游戏徽章。 - 线条更轻,图形更偏平台化和消费级,不做重游戏徽章。
- 色彩采用珊瑚粉、暖金、浅青和深色细线,表达“点”消费单位与灵感生长。 - 色彩采用珊瑚粉、暖金、浅青和深色细线,表达“点”消费单位与灵感生长。
适合场景: 适合场景:
@@ -64,7 +64,7 @@
设计含义: 设计含义:
每个点都是一次生成、一次灵感、一次世界推进。多点汇聚成梦,呼应“百梦”里从许多小创意生长出完整作品的路径。 每个点都是一次生成、一次灵感、一次世界推进。多点汇聚成梦,呼应“陶泥儿”里从许多小创意生长出完整作品的路径。
## 5. 方案 D像素剧场 ## 5. 方案 D像素剧场
@@ -82,11 +82,11 @@
设计含义: 设计含义:
舞台代表演出,卷轴代表叙事,星形光标代表 AI 与玩家选择。它让百梦看起来仍然属于游戏和互动内容,而不是泛 AI 工具。 舞台代表演出,卷轴代表叙事,星形光标代表 AI 与玩家选择。它让陶泥儿看起来仍然属于游戏和互动内容,而不是泛 AI 工具。
## 6. 生成说明 ## 6. 生成说明
本次推荐先用 `gpt-image-2` 生成 4 张 `1024x1024` 方形草案。由于图片模型对中文文字的稳定性有限,首轮应优先验证“图形标识”而不是直接把“百梦”两个字烘焙进图片。最终产品落地时,建议使用真实前端字体或 SVG 字形承载“百梦”字标,把生成图作为图形标志参考。 本次推荐先用 `gpt-image-2` 生成 4 张 `1024x1024` 方形草案。由于图片模型对中文文字的稳定性有限,首轮应优先验证“图形标识”而不是直接把“陶泥儿”两个字烘焙进图片。最终产品落地时,建议使用真实前端字体或 SVG 字形承载“陶泥儿”字标,把生成图作为图形标志参考。
## 7. 女性友好与全年龄潮流版补充 ## 7. 女性友好与全年龄潮流版补充
@@ -96,8 +96,8 @@
- 字形更圆润,减少尖锐笔锋、黑底压迫感和玄幻气质。 - 字形更圆润,减少尖锐笔锋、黑底压迫感和玄幻气质。
- 色彩从黑白、金色、深墨切换到奶油白、莓果粉、薰衣草紫、薄荷青。 - 色彩从黑白、金色、深墨切换到奶油白、莓果粉、薰衣草紫、薄荷青。
- 允许轻量梦泡、云朵、柔软点等符号,但不堆叠插画。 - 允许轻量梦泡、云朵、柔软点等符号,但不堆叠插画。
- 保留“百梦”中文字标作为主识别,图标可作为 App icon 或社交头像补充。 - 保留“陶泥儿”中文字标作为主识别,图标可作为 App icon 或社交头像补充。
本轮生成 prompt 本轮生成 prompt

View File

@@ -48,7 +48,7 @@
1. 发现页隐藏“寓教于乐”标签; 1. 发现页隐藏“寓教于乐”标签;
2. 隐藏“寓教于乐”标签下内容; 2. 隐藏“寓教于乐”标签下内容;
3. 该内容线内容不进入推荐、今日、分类、排行和搜索结果; 3. 该内容线内容不进入推荐、今日、分类、排行和搜索结果;
4. 该内容线内容完全不可见,公开作品搜索、作品号搜索直达、公开详情深链、浏览历史入口等平台公开入口都不能打开该内容。 4. 该内容线内容完全不可见,公开作品搜索、作品号搜索直达、公开详情深链、浏览历史入口、创作入口和创作页作品架等平台入口都不能打开或展示该内容。
## 4. 内容识别规则 ## 4. 内容识别规则
@@ -114,4 +114,23 @@ no
4. `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx` 已复用同一过滤 helper避免推荐运行态自动启动寓教于乐作品并在公开详情、作品号直达和公开详情深链等公开入口保留不可见保护。 4. `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx` 已复用同一过滤 helper避免推荐运行态自动启动寓教于乐作品并在公开详情、作品号直达和公开详情深链等公开入口保留不可见保护。
5. 浏览历史入口会优先按当前公开作品集合匹配作品标签;匹配到“寓教于乐”作品且开关关闭时不再展示历史入口。 5. 浏览历史入口会优先按当前公开作品集合匹配作品标签;匹配到“寓教于乐”作品且开关关闭时不再展示历史入口。
6. `/child-motion-demo` 本地动作 Demo 直达路由也复用同一开关;开关关闭时不匹配独立 Demo 应用,回落到主站入口。 6. `/child-motion-demo` 本地动作 Demo 直达路由也复用同一开关;开关关闭时不匹配独立 Demo 应用,回落到主站入口。
7. 定向回归覆盖在 `src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx``src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx``src/components/platform-entry/platformEdutainmentVisibility.test.ts``src/routing/appRoutes.test.ts`包含频道顺序、开关关闭、普通列表过滤、搜索过滤、作品号直达拦截、Demo 直达路由拦截和精确标签识别。 7. `宝贝识物` 创作入口和创作页作品架也复用同一开关;开关关闭时不展示模板入口,也不展示本地宝贝识物草稿或已发布卡片。
8. 定向回归覆盖在 `src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx``src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx``src/components/platform-entry/platformEdutainmentVisibility.test.ts``src/components/platform-entry/platformEntryCreationTypes.test.ts``src/routing/appRoutes.test.ts`包含频道顺序、开关关闭、普通列表过滤、搜索过滤、作品号直达拦截、Demo 直达路由拦截、创作入口隐藏和精确标签识别。
## 9. 第 4 项作品架 / 广场接入边界
`宝贝识物` 首关的公开作品展示接入按以下口径收口:
1. 平台公共作品模型新增 `sourceType = edutainment`,当前只承接 `templateId = baby-object-match``templateName = 宝贝识物`
2. `宝贝识物` 作品仍必须携带精确等于“寓教于乐”的公开标签,才会进入“发现 / 寓教于乐”频道。
3. `宝贝识物` 不因为模板名自动归入寓教于乐,也不因为近似标签归入寓教于乐。
4. 第 4 项只负责公开作品卡片、发现页专属频道、公开详情、分享作品号和开关隐藏保护。
5. 创作模板、image-2 资产生成、发布接口、运行时开始游戏和关卡状态由对应线程接入;当前公共作品卡直接透传后续数据源提供的 `publicWorkCode`,不在前端新增最终作品号前缀规则。
6. 在创作和运行时链路真正接入前,公开详情内的启动、改造、编辑和点赞只做保护性占位,不新增玩法规则。
当前工程落点:
1. `src/components/rpg-entry/rpgEntryWorldPresentation.ts` 定义 `PlatformEdutainmentGalleryCard``isEdutainmentGalleryEntry`
2. `src/components/rpg-entry/RpgEntryHomeView.tsx``宝贝识物` 卡片识别为寓教于乐公开作品,并继续从推荐、今日、分类、排行和搜索结果中过滤。
3. `src/components/platform-entry/PlatformWorkDetailView.tsx` 在公开详情中显示 `宝贝识物` 类型标签,并继续复用作品号复制和分享链路。
4. `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx` 已识别 `edutainment` 公共作品,避免落入 RPG 默认详情、推荐运行态或错误的改造链路。

View File

@@ -1,4 +1,4 @@
# 自定义世界百梦主输入与 AI 分工边界设计 # 自定义世界陶泥儿主输入与 AI 分工边界设计
更新时间:`2026-04-06` 更新时间:`2026-04-06`
@@ -6,9 +6,9 @@
这份文档回答一个非常关键的问题: 这份文档回答一个非常关键的问题:
**在“低创作门槛、高创作自由度”的前提下,自定义世界里哪些内容应该交给百梦主直接定义,哪些内容应该交给 AI 和系统完成。** **在“低创作门槛、高创作自由度”的前提下,自定义世界里哪些内容应该交给陶泥儿主直接定义,哪些内容应该交给 AI 和系统完成。**
这里默认我们的百梦主: 这里默认我们的陶泥儿主:
- 不需要有专业作家背景 - 不需要有专业作家背景
- 不需要有专业游戏设计背景 - 不需要有专业游戏设计背景
@@ -16,33 +16,33 @@
一句话目标: 一句话目标:
**让百梦主把精力放在“决定这个世界为什么值得被创作”,把 AI 用在“把这个世界展开、编译、铺开、校验、补足”。** **让陶泥儿主把精力放在“决定这个世界为什么值得被创作”,把 AI 用在“把这个世界展开、编译、铺开、校验、补足”。**
## 1. 总体结论 ## 1. 总体结论
自定义世界的分工边界应该遵守 3 条硬原则: 自定义世界的分工边界应该遵守 3 条硬原则:
1. 灵魂归百梦主,杂活归 AI。 1. 灵魂归陶泥儿主,杂活归 AI。
- 凡是决定作品气质、主题、冲突、人物关系、审美方向的内容,都应由百梦主掌握。 - 凡是决定作品气质、主题、冲突、人物关系、审美方向的内容,都应由陶泥儿主掌握。
2. 重点对象归百梦主,长尾铺量归 AI。 2. 重点对象归陶泥儿主,长尾铺量归 AI。
- 百梦主应重点塑造少量关键角色、关键地点、关键冲突、关键意象,而不是被迫手填几十个 NPC、几十个场景、几百条描述。 - 陶泥儿主应重点塑造少量关键角色、关键地点、关键冲突、关键意象,而不是被迫手填几十个 NPC、几十个场景、几百条描述。
3. 决策归百梦主,编译归 AI / 系统。 3. 决策归陶泥儿主,编译归 AI / 系统。
- 百梦主负责说“这个世界要成为什么样”AI / 系统负责把它编译成可运行的数据、规则、文本、关系钩子和运行时结构。 - 陶泥儿主负责说“这个世界要成为什么样”AI / 系统负责把它编译成可运行的数据、规则、文本、关系钩子和运行时结构。
这意味着: 这意味着:
- 百梦主应该主要编辑“高杠杆创作锚点” - 陶泥儿主应该主要编辑“高杠杆创作锚点”
- AI 应该主要承担“批量展开 + 结构编译 + 一致性维护 + 专业执行” - AI 应该主要承担“批量展开 + 结构编译 + 一致性维护 + 专业执行”
## 2. 什么内容应该交给百梦 ## 2. 什么内容应该交给陶泥儿
真正应该交给百梦主的,不是大量表格字段,而是下面这些会显著决定作品质量、且 AI 不擅长替代的内容。 真正应该交给陶泥儿主的,不是大量表格字段,而是下面这些会显著决定作品质量、且 AI 不擅长替代的内容。
## 2.1 世界核心命题 ## 2.1 世界核心命题
百梦主应该直接定义: 陶泥儿主应该直接定义:
- 这个世界的一句话设定 - 这个世界的一句话设定
- 这个世界最吸引人的核心幻想 - 这个世界最吸引人的核心幻想
@@ -56,7 +56,7 @@
## 2.2 主题、气质与边界 ## 2.2 主题、气质与边界
百梦主应该直接定义: 陶泥儿主应该直接定义:
- 主题关键词 - 主题关键词
- 情绪基调 - 情绪基调
@@ -71,7 +71,7 @@
## 2.3 玩家身份与开局处境 ## 2.3 玩家身份与开局处境
百梦主应该直接定义: 陶泥儿主应该直接定义:
- 玩家扮演的是什么人 - 玩家扮演的是什么人
- 玩家一开始最缺什么、最想要什么 - 玩家一开始最缺什么、最想要什么
@@ -85,7 +85,7 @@
## 2.4 核心冲突与关键势力 ## 2.4 核心冲突与关键势力
百梦主应该直接定义少量高价值内容: 陶泥儿主应该直接定义少量高价值内容:
- 世界当前最重要的 `2~4` 条明面冲突 - 世界当前最重要的 `2~4` 条明面冲突
- 世界背后最关键的 `1~3` 条暗面问题 - 世界背后最关键的 `1~3` 条暗面问题
@@ -96,13 +96,13 @@
- 冲突结构决定世界是否“有戏” - 冲突结构决定世界是否“有戏”
- 势力关系是 AI 最容易写散、写平、写成百科介绍的部分 - 势力关系是 AI 最容易写散、写平、写成百科介绍的部分
- 这一层由百梦主把握,才能真正提高作品的辨识度 - 这一层由陶泥儿主把握,才能真正提高作品的辨识度
## 2.5 关键角色与关系张力 ## 2.5 关键角色与关系张力
百梦主应该直接定义少量关键角色,而不是所有 NPC。 陶泥儿主应该直接定义少量关键角色,而不是所有 NPC。
建议重点交给百梦主的,是: 建议重点交给陶泥儿主的,是:
- `3~8` 个关键角色 - `3~8` 个关键角色
- 玩家与这些人的潜在关系 - 玩家与这些人的潜在关系
@@ -113,11 +113,11 @@
- 角色关系是最能显著提升作品质量的部分之一 - 角色关系是最能显著提升作品质量的部分之一
- 这也是 AI 最容易写得“完整但无味”的部分 - 这也是 AI 最容易写得“完整但无味”的部分
- 百梦主不需要写长篇背景,但应掌握这些角色真正的关系骨架 - 陶泥儿主不需要写长篇背景,但应掌握这些角色真正的关系骨架
## 2.6 关键地点与空间记忆点 ## 2.6 关键地点与空间记忆点
百梦主应该直接定义: 陶泥儿主应该直接定义:
- `4~12` 个关键地点 / 区域 / 地标 - `4~12` 个关键地点 / 区域 / 地标
- 这些地方为什么重要 - 这些地方为什么重要
@@ -131,7 +131,7 @@
## 2.7 标志性意象、物件、怪物、制度与规则 ## 2.7 标志性意象、物件、怪物、制度与规则
百梦主应该优先控制世界里最能代表它的东西: 陶泥儿主应该优先控制世界里最能代表它的东西:
- 标志性物件 - 标志性物件
- 标志性怪物 / 生物 - 标志性怪物 / 生物
@@ -144,9 +144,9 @@
- 这些内容决定世界的“手感” - 这些内容决定世界的“手感”
- 它们不是普通细节,而是会反复影响命名、剧情、视觉、对话与玩法解释的母题 - 它们不是普通细节,而是会反复影响命名、剧情、视觉、对话与玩法解释的母题
## 2.8 百梦主应直接控制的“禁止事项” ## 2.8 陶泥儿主应直接控制的“禁止事项”
百梦主必须能明确锁定: 陶泥儿主必须能明确锁定:
- 什么绝对不能改 - 什么绝对不能改
- 什么不能被 AI 自动扩写到别的方向 - 什么不能被 AI 自动扩写到别的方向
@@ -156,7 +156,7 @@
原因: 原因:
- 高自由度不等于所有内容都开放漂移 - 高自由度不等于所有内容都开放漂移
- 如果没有“锁定机制”AI 会把百梦主真正关心的内容稀释掉 - 如果没有“锁定机制”AI 会把陶泥儿主真正关心的内容稀释掉
## 3. 什么内容应该交给 AI 和系统 ## 3. 什么内容应该交给 AI 和系统
@@ -176,7 +176,7 @@
原因: 原因:
- 这些内容数量大、重复度高 - 这些内容数量大、重复度高
- 它们需要“贴合世界”,但不需要都由百梦主逐个手写 - 它们需要“贴合世界”,但不需要都由陶泥儿主逐个手写
- AI 很适合做“围绕锚点的批量铺量” - AI 很适合做“围绕锚点的批量铺量”
## 3.2 从创作锚点到系统结构的编译 ## 3.2 从创作锚点到系统结构的编译
@@ -186,7 +186,7 @@
- 从自然语言世界设定中提取题材词汇 - 从自然语言世界设定中提取题材词汇
- 从关键冲突中编译出世界叙事图谱 - 从关键冲突中编译出世界叙事图谱
- 从关键角色卡编译出角色叙事档案 - 从关键角色卡编译出角色叙事档案
-百梦主输入里自动生成标签、钩子、隐藏线索、章节摘要 -陶泥儿主输入里自动生成标签、钩子、隐藏线索、章节摘要
- 从地点和关系中编译出场景连接、事件触发和叙事回响 - 从地点和关系中编译出场景连接、事件触发和叙事回响
对应当前仓库,下面这些结构更适合由 AI / 系统生成,而不是让玩家直接编辑: 对应当前仓库,下面这些结构更适合由 AI / 系统生成,而不是让玩家直接编辑:
@@ -203,7 +203,7 @@
原因: 原因:
- 这些是运行时结构,不是百梦主真正想表达的作品内容 - 这些是运行时结构,不是陶泥儿主真正想表达的作品内容
- 直接暴露给玩家,会把创作过程变成专业数据填表 - 直接暴露给玩家,会把创作过程变成专业数据填表
## 3.3 专业化、规则化的任务 ## 3.3 专业化、规则化的任务
@@ -223,7 +223,7 @@
原因: 原因:
- 这些工作要么重复、要么专业、要么容易做脏活累活 - 这些工作要么重复、要么专业、要么容易做脏活累活
- 让非专业百梦主处理,会显著提高门槛,却不一定显著提高质量 - 让非专业陶泥儿主处理,会显著提高门槛,却不一定显著提高质量
## 3.4 一致性、纠错与查漏补缺 ## 3.4 一致性、纠错与查漏补缺
@@ -240,15 +240,15 @@
原因: 原因:
- 这是 AI 比人更适合做的“维护型工作” - 这是 AI 比人更适合做的“维护型工作”
- 它属于创作支持,不属于百梦主必须亲手完成的创作 - 它属于创作支持,不属于陶泥儿主必须亲手完成的创作
## 4. 最合理的边界不是二分法,而是三层分工 ## 4. 最合理的边界不是二分法,而是三层分工
自定义世界最合理的结构不是“玩家写”与“AI 写”的简单二选一,而是三层。 自定义世界最合理的结构不是“玩家写”与“AI 写”的简单二选一,而是三层。
## 4.1 第一层:百梦主必控层 ## 4.1 第一层:陶泥儿主必控层
这一层必须给百梦主高自由度,且能被锁定: 这一层必须给陶泥儿主高自由度,且能被锁定:
- 世界核心命题 - 世界核心命题
- 主题与气质 - 主题与气质
@@ -264,9 +264,9 @@
**少而重。** **少而重。**
## 4.2 第二层:百梦主可选强化层 ## 4.2 第二层:陶泥儿主可选强化层
这一层不应强制填写,但应该允许百梦主继续深挖: 这一层不应强制填写,但应该允许陶泥儿主继续深挖:
- 明线 / 暗线种子 - 明线 / 暗线种子
- 角色之间的旧事 - 角色之间的旧事
@@ -301,17 +301,17 @@
## 5. 具体模块的建议归属 ## 5. 具体模块的建议归属
| 模块 | 建议归属 | 百梦主应控制什么 | AI / 系统应负责什么 | | 模块 | 建议归属 | 陶泥儿主应控制什么 | AI / 系统应负责什么 |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| 世界一句话设定、核心幻想、核心卖点 | 百梦主直接控制 | 直接写、直接改、可锁定 | 给出备选表述和扩展方向 | | 世界一句话设定、核心幻想、核心卖点 | 陶泥儿主直接控制 | 直接写、直接改、可锁定 | 给出备选表述和扩展方向 |
| 主题、基调、审美、禁忌 | 百梦主直接控制 | 选择 / 改写 / 锁定 | 生成风格词、避雷词、提示词约束 | | 主题、基调、审美、禁忌 | 陶泥儿主直接控制 | 选择 / 改写 / 锁定 | 生成风格词、避雷词、提示词约束 |
| 玩家身份、开局处境、玩家目标 | 百梦主直接控制 | 直接定义 | 补足开局钩子和初始叙事包装 | | 玩家身份、开局处境、玩家目标 | 陶泥儿主直接控制 | 直接定义 | 补足开局钩子和初始叙事包装 |
| 关键势力与核心冲突 | 百梦主控AI 辅助 | 定义核心关系和立场 | 扩展冲突支路、生成世界线程 | | 关键势力与核心冲突 | 陶泥儿主控AI 辅助 | 定义核心关系和立场 | 扩展冲突支路、生成世界线程 |
| 关键角色 | 百梦主控AI 辅助 | 定义角色骨架、关系张力、秘密方向 | 生成长背景、章节拆分、技能、物品、叙事档案 | | 关键角色 | 陶泥儿主控AI 辅助 | 定义角色骨架、关系张力、秘密方向 | 生成长背景、章节拆分、技能、物品、叙事档案 |
| 关键地点 | 百梦主控AI 辅助 | 定义地点意义、气氛、秘密 | 扩展场景细节、连接关系、遭遇分布 | | 关键地点 | 陶泥儿主控AI 辅助 | 定义地点意义、气氛、秘密 | 扩展场景细节、连接关系、遭遇分布 |
| 标志性物件 / 怪物 / 制度 / 规则 | 百梦主控AI 辅助 | 定义代表性要素与硬边界 | 扩展变体、命名、说明、运行时挂钩 | | 标志性物件 / 怪物 / 制度 / 规则 | 陶泥儿主控AI 辅助 | 定义代表性要素与硬边界 | 扩展变体、命名、说明、运行时挂钩 |
| 普通 NPC / 路人 / 杂兵 / 次级地点 | 主要交给 AI | 仅在需要时抽查或替换 | 批量生成与风格保持 | | 普通 NPC / 路人 / 杂兵 / 次级地点 | 主要交给 AI | 仅在需要时抽查或替换 | 批量生成与风格保持 |
| 角色长背景、章节 teaser、context snippet | 主要交给 AI | 百梦主只改关键角色即可 | 自动拆章、压缩、解锁节奏整理 | | 角色长背景、章节 teaser、context snippet | 主要交给 AI | 陶泥儿主只改关键角色即可 | 自动拆章、压缩、解锁节奏整理 |
| 技能、初始物品、标签、构筑倾向 | 主要交给 AI / 系统 | 提供偏好或少量 override | 按角色和世界规则自动编译 | | 技能、初始物品、标签、构筑倾向 | 主要交给 AI / 系统 | 提供偏好或少量 override | 按角色和世界规则自动编译 |
| 世界图谱、知识事实、可见性、导演指令 | AI / 系统内部层 | 不应默认暴露给玩家 | 运行时编译与维护 | | 世界图谱、知识事实、可见性、导演指令 | AI / 系统内部层 | 不应默认暴露给玩家 | 运行时编译与维护 |
| 一致性检查、冲突检查、越权检查 | AI / 系统内部层 | 查看报告、决定是否采纳修改 | 自动扫描并提出修正建议 | | 一致性检查、冲突检查、越权检查 | AI / 系统内部层 | 查看报告、决定是否采纳修改 | 自动扫描并提出修正建议 |
@@ -328,7 +328,7 @@
- 精确数值型 build 倾向 - 精确数值型 build 倾向
- 复杂掉落预算 - 复杂掉落预算
更合理的做法是让百梦主填写直觉表达,例如: 更合理的做法是让陶泥儿主填写直觉表达,例如:
- `初见就戒备` - `初见就戒备`
- `容易合作` - `容易合作`
@@ -351,7 +351,7 @@
原因: 原因:
- 这些字段属于系统运行结构,不属于百梦主自然的创作语言 - 这些字段属于系统运行结构,不属于陶泥儿主自然的创作语言
- 直接让玩家填,会把工具变成只有懂系统的人才能用 - 直接让玩家填,会把工具变成只有懂系统的人才能用
## 6.3 不应该要求玩家逐个补完所有人物设定字段 ## 6.3 不应该要求玩家逐个补完所有人物设定字段
@@ -378,7 +378,7 @@
## 7. 推荐的创作输入形态 ## 7. 推荐的创作输入形态
要让非专业百梦主也能高自由度创作,输入形态必须改成“自然语言创作卡”,而不是“系统字段表单”。 要让非专业陶泥儿主也能高自由度创作,输入形态必须改成“自然语言创作卡”,而不是“系统字段表单”。
## 7.1 世界层卡片 ## 7.1 世界层卡片
@@ -397,10 +397,10 @@
## 7.2 每张卡片都允许 3 种输入方式 ## 7.2 每张卡片都允许 3 种输入方式
1. 一句话自由输入 1. 一句话自由输入
- 适合低门槛百梦 - 适合低门槛陶泥儿
2. 标签 / 选项 / 语气滑条 2. 标签 / 选项 / 语气滑条
- 适合不想写太多字的百梦 - 适合不想写太多字的陶泥儿
3. 高级补充 3. 高级补充
- 适合愿意继续深挖的人 - 适合愿意继续深挖的人
@@ -414,7 +414,7 @@
这是高创作自由度里非常关键的一点。 这是高创作自由度里非常关键的一点。
百梦主应当能: 陶泥儿主应当能:
- 锁定一个角色 - 锁定一个角色
- 锁定一个地点 - 锁定一个地点
@@ -422,13 +422,13 @@
- 只重生成未锁定部分 - 只重生成未锁定部分
- 围绕锁定内容重写其余世界 - 围绕锁定内容重写其余世界
否则百梦主每次调用 AI都会有“好不容易想好的东西被洗掉”的感受。 否则陶泥儿主每次调用 AI都会有“好不容易想好的东西被洗掉”的感受。
## 8. 面向当前仓库的结构映射建议 ## 8. 面向当前仓库的结构映射建议
为了便于后续落实现有系统,这份边界建议可以直接映射到当前结构: 为了便于后续落实现有系统,这份边界建议可以直接映射到当前结构:
## 8.1 百梦主输入层 ## 8.1 陶泥儿主输入层
建议主要映射到: 建议主要映射到:
@@ -445,7 +445,7 @@
## 8.2 AI 编译层 ## 8.2 AI 编译层
由 AI / 系统从百梦主输入自动补出: 由 AI / 系统从陶泥儿主输入自动补出:
- `themePack` - `themePack`
- `storyGraph` - `storyGraph`
@@ -465,7 +465,7 @@
- `CarrierStoryFingerprint` - `CarrierStoryFingerprint`
- `StorySignal` - `StorySignal`
这些内容应该是“系统如何把世界跑起来”,不是“百梦主必须亲手写完的创作内容”。 这些内容应该是“系统如何把世界跑起来”,不是“陶泥儿主必须亲手写完的创作内容”。
## 9. 产品层面的最终结论 ## 9. 产品层面的最终结论
@@ -480,12 +480,12 @@
它应该做成这样: 它应该做成这样:
1. 百梦主决定世界的灵魂锚点。 1. 陶泥儿主决定世界的灵魂锚点。
2. 百梦主重点塑造少量关键人、关键地、关键冲突、关键物。 2. 陶泥儿主重点塑造少量关键人、关键地、关键冲突、关键物。
3. AI 围绕这些锚点批量展开长尾内容。 3. AI 围绕这些锚点批量展开长尾内容。
4. 系统把这些内容编译成可运行的图谱、可见性、任务、物件和关系结构。 4. 系统把这些内容编译成可运行的图谱、可见性、任务、物件和关系结构。
5. 百梦主随时可以锁定核心创意,并局部重生成其余部分。 5. 陶泥儿主随时可以锁定核心创意,并局部重生成其余部分。
一句话收束: 一句话收束:
**百梦主应该写“这个世界为什么动人”AI 应该负责“让这个世界长出来并跑起来”。** **陶泥儿主应该写“这个世界为什么动人”AI 应该负责“让这个世界长出来并跑起来”。**

View File

@@ -6,17 +6,17 @@
这份文档用于回答一个更具体的问题: 这份文档用于回答一个更具体的问题:
**参考 RPG 专业剧情策划全流程后,在自定义世界创作工具里,哪些设定必须要求百梦主手动填写,哪些设定应该由 AI 先生成但允许百梦主修改,哪些设定应完全交给系统托管,才能在“尽可能降低门槛”和“尽可能提高作品质量”之间取一个平衡。** **参考 RPG 专业剧情策划全流程后,在自定义世界创作工具里,哪些设定必须要求陶泥儿主手动填写,哪些设定应该由 AI 先生成但允许陶泥儿主修改,哪些设定应完全交给系统托管,才能在“尽可能降低门槛”和“尽可能提高作品质量”之间取一个平衡。**
这份文档不再只回答“百梦主与 AI 怎么分工”,而是进一步把创作工作台收束成一个更可执行的三层输入结构: 这份文档不再只回答“陶泥儿主与 AI 怎么分工”,而是进一步把创作工作台收束成一个更可执行的三层输入结构:
1. 百梦主必须手填的高杠杆锚点 1. 陶泥儿主必须手填的高杠杆锚点
2. AI 先生成、百梦主可修改的内容草稿层 2. AI 先生成、陶泥儿主可修改的内容草稿层
3. 系统自动编译和运行的托管层 3. 系统自动编译和运行的托管层
一句话结论: 一句话结论:
**让百梦主只负责决定作品的灵魂、视角、冲突和关系钩子,让 AI 负责把这些锚点展开成可编辑的剧情草稿,让系统负责把草稿编译成可运行的结构。** **让陶泥儿主只负责决定作品的灵魂、视角、冲突和关系钩子,让 AI 负责把这些锚点展开成可编辑的剧情草稿,让系统负责把草稿编译成可运行的结构。**
--- ---
@@ -25,27 +25,27 @@
这套平衡设计要同时满足 5 个目标: 这套平衡设计要同时满足 5 个目标:
1. 低门槛 1. 低门槛
-百梦主不需要写长篇设定,也不需要理解底层系统结构。 -陶泥儿主不需要写长篇设定,也不需要理解底层系统结构。
2. 高辨识度 2. 高辨识度
- 百梦主写出来的世界,不应该只是“像一个世界”,而应该保留明显的个人方向。 - 陶泥儿主写出来的世界,不应该只是“像一个世界”,而应该保留明显的个人方向。
3. 高可编辑性 3. 高可编辑性
- AI 不能一次生成后就不可控,百梦主必须能改关键对象、关键关系和关键章节。 - AI 不能一次生成后就不可控,陶泥儿主必须能改关键对象、关键关系和关键章节。
4. 高稳定性 4. 高稳定性
- 任务、章节、关系、物件和可见性等运行层结构不能依赖百梦主手填专业字段。 - 任务、章节、关系、物件和可见性等运行层结构不能依赖陶泥儿主手填专业字段。
5. 可扩展 5. 可扩展
- 愿意深挖的百梦主可以继续补充世界上限,不愿深挖的人也能快速产出质量不错的作品。 - 愿意深挖的陶泥儿主可以继续补充世界上限,不愿深挖的人也能快速产出质量不错的作品。
--- ---
## 2. 核心原则 ## 2. 核心原则
## 2.1 百梦主手填的必须是“高杠杆决策”,不是“高工作量字段” ## 2.1 陶泥儿主手填的必须是“高杠杆决策”,不是“高工作量字段”
应该要求百梦主手填的内容,必须同时满足下面两个条件: 应该要求陶泥儿主手填的内容,必须同时满足下面两个条件:
1. 会显著决定作品气质和辨识度 1. 会显著决定作品气质和辨识度
2. AI 很难替代判断 2. AI 很难替代判断
@@ -67,9 +67,9 @@
- 章节拆分 - 章节拆分
- 运行时信号结构 - 运行时信号结构
## 2.2 百梦主可改层应该承接“专业策划初稿”,而不是“原始底层字段” ## 2.2 陶泥儿主可改层应该承接“专业策划初稿”,而不是“原始底层字段”
AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而应该是一批已经成形的内容卡片,例如: AI 生成后允许陶泥儿主修改的,不应该是一堆技术型字段,而应该是一批已经成形的内容卡片,例如:
- 关键角色卡 - 关键角色卡
- 势力卡 - 势力卡
@@ -81,11 +81,11 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
也就是说: 也就是说:
**AI 先给百梦主一个像策划初稿的东西,而不是给一堆系统字段让百梦主自己拼。** **AI 先给陶泥儿主一个像策划初稿的东西,而不是给一堆系统字段让陶泥儿主自己拼。**
## 2.3 系统托管层必须彻底隐藏专业运行结构 ## 2.3 系统托管层必须彻底隐藏专业运行结构
以下这类结构不应该默认要求百梦主理解或编辑: 以下这类结构不应该默认要求陶泥儿主理解或编辑:
- `ThemePack` - `ThemePack`
- `WorldStoryGraph` - `WorldStoryGraph`
@@ -98,7 +98,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
- 稀有度映射 - 稀有度映射
- 掉落和 build 权重 - 掉落和 build 权重
百梦主应该编辑的是自然语言与内容卡,而不是运行时图结构。 陶泥儿主应该编辑的是自然语言与内容卡,而不是运行时图结构。
## 2.4 先少量必填,再逐层展开 ## 2.4 先少量必填,再逐层展开
@@ -107,9 +107,9 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
```text ```text
先填最小必填卡 先填最小必填卡
-> AI 生成世界初稿 -> AI 生成世界初稿
-> 百梦主修改关键对象 -> 陶泥儿主修改关键对象
-> 系统继续展开长尾 -> 系统继续展开长尾
-> 百梦主决定是否进入高级补充 -> 陶泥儿主决定是否进入高级补充
``` ```
## 2.5 默认清爽,深度能力后置 ## 2.5 默认清爽,深度能力后置
@@ -127,27 +127,27 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
## 3. 最终建议:三层分工 ## 3. 最终建议:三层分工
## 3.1 第一层:必须要求百梦主手动填写 ## 3.1 第一层:必须要求陶泥儿主手动填写
这一层只保留最影响作品质量的高杠杆锚点,建议默认强制填写 6 张卡。 这一层只保留最影响作品质量的高杠杆锚点,建议默认强制填写 6 张卡。
## 3.2 第二层AI 生成后支持百梦主修改 ## 3.2 第二层AI 生成后支持陶泥儿主修改
这一层由 AI 根据第一层锚点自动展开成专业剧情策划初稿,百梦主可以逐项修改、锁定、局部重生成。 这一层由 AI 根据第一层锚点自动展开成专业剧情策划初稿,陶泥儿主可以逐项修改、锁定、局部重生成。
## 3.3 第三层:其余都交给系统 ## 3.3 第三层:其余都交给系统
这一层是把前两层编译成可运行游戏结构所需的系统字段、数值和运行时指令,默认不要求百梦主处理。 这一层是把前两层编译成可运行游戏结构所需的系统字段、数值和运行时指令,默认不要求陶泥儿主处理。
--- ---
## 4. 最低门槛方案:只强制手填 6 张卡 ## 4. 最低门槛方案:只强制手填 6 张卡
如果目标是尽可能降低门槛,同时又保留作品辨识度,建议只强制百梦主填写以下 6 张卡。 如果目标是尽可能降低门槛,同时又保留作品辨识度,建议只强制陶泥儿主填写以下 6 张卡。
## 4.1 卡 1世界一句话与核心幻想 ## 4.1 卡 1世界一句话与核心幻想
百梦主必须手填: 陶泥儿主必须手填:
- 世界一句话设定 - 世界一句话设定
- 玩家来到这个世界最想体验的感觉 - 玩家来到这个世界最想体验的感觉
@@ -165,7 +165,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
## 4.2 卡 2玩家身份与开局困境 ## 4.2 卡 2玩家身份与开局困境
百梦主必须手填: 陶泥儿主必须手填:
- 玩家是谁 - 玩家是谁
- 玩家开局最缺什么 - 玩家开局最缺什么
@@ -179,7 +179,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
## 4.3 卡 3主题气质与禁忌边界 ## 4.3 卡 3主题气质与禁忌边界
百梦主必须手填: 陶泥儿主必须手填:
- 主题关键词 - 主题关键词
- 情绪基调 - 情绪基调
@@ -199,7 +199,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
## 4.4 卡 4核心冲突 ## 4.4 卡 4核心冲突
百梦主必须手填: 陶泥儿主必须手填:
- 当前世界最重要的 `1~3` 个明面冲突 - 当前世界最重要的 `1~3` 个明面冲突
- 至少 `1` 个隐藏问题或暗面危机 - 至少 `1` 个隐藏问题或暗面危机
@@ -212,9 +212,9 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
## 4.5 卡 5关键关系钩子 ## 4.5 卡 5关键关系钩子
这里不强制百梦主一开始填写完整角色档案,只要求填写更高杠杆的“关系骨架”。 这里不强制陶泥儿主一开始填写完整角色档案,只要求填写更高杠杆的“关系骨架”。
百梦主必须手填: 陶泥儿主必须手填:
- `2~4` 条关键关系钩子 - `2~4` 条关键关系钩子
- 每条钩子至少说明: - 每条钩子至少说明:
@@ -229,7 +229,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
## 4.6 卡 6标志性要素与硬规则 ## 4.6 卡 6标志性要素与硬规则
百梦主必须手填: 陶泥儿主必须手填:
- `2~5` 个标志性要素 - `2~5` 个标志性要素
- 物件 - 物件
@@ -247,11 +247,11 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
--- ---
## 5. 不建议强制手填,但应该让 AI 生成后支持百梦主修改的设定 ## 5. 不建议强制手填,但应该让 AI 生成后支持陶泥儿主修改的设定
这一层是平衡“低门槛”和“高质量”的关键。 这一层是平衡“低门槛”和“高质量”的关键。
百梦主不需要从零填写这些内容,但 AI 生成后必须能看、能改、能锁定、能局部重生成。 陶泥儿主不需要从零填写这些内容,但 AI 生成后必须能看、能改、能锁定、能局部重生成。
## 5.1 世界外观层 ## 5.1 世界外观层
@@ -282,7 +282,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
原因: 原因:
- 势力很重要,但让新手一开始手写完整势力表太重 - 势力很重要,但让新手一开始手写完整势力表太重
- 更合理的做法是让 AI 基于核心冲突先出草稿,再由百梦主修正 - 更合理的做法是让 AI 基于核心冲突先出草稿,再由陶泥儿主修正
## 5.3 关键角色层 ## 5.3 关键角色层
@@ -302,8 +302,8 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
原因: 原因:
- 百梦主已经通过“关系钩子”给出最关键的人物骨架 - 陶泥儿主已经通过“关系钩子”给出最关键的人物骨架
- AI 负责把钩子展开成可编辑角色卡,百梦主再做精修 - AI 负责把钩子展开成可编辑角色卡,陶泥儿主再做精修
## 5.4 关键地点层 ## 5.4 关键地点层
@@ -319,7 +319,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
原因: 原因:
- 地点是世界感的重要来源 - 地点是世界感的重要来源
- 但新百梦主未必能一开始就写出完整地点网络 - 但新陶泥儿主未必能一开始就写出完整地点网络
## 5.5 世界线程层 ## 5.5 世界线程层
@@ -335,7 +335,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
原因: 原因:
- 线程是专业剧情结构,适合 AI 先搭骨架 - 线程是专业剧情结构,适合 AI 先搭骨架
-百梦主必须有权修正哪条线更重要、哪条线该隐藏 -陶泥儿主必须有权修正哪条线更重要、哪条线该隐藏
## 5.6 主线章节层 ## 5.6 主线章节层
@@ -350,9 +350,9 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
原因: 原因:
- 百梦主已经给出了世界目标、冲突和关系 - 陶泥儿主已经给出了世界目标、冲突和关系
- AI 可以先把它们编成主线章节初稿 - AI 可以先把它们编成主线章节初稿
- 百梦主再选择保留、删减或重排 - 陶泥儿主再选择保留、删减或重排
## 5.7 支线、角色线、阵营线层 ## 5.7 支线、角色线、阵营线层
@@ -367,7 +367,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
原因: 原因:
- 这是最适合 AI 拉开内容宽度的部分 - 这是最适合 AI 拉开内容宽度的部分
- 也是最需要百梦主局部精修的部分 - 也是最需要陶泥儿主局部精修的部分
## 5.8 场景章节层 ## 5.8 场景章节层
@@ -384,7 +384,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
原因: 原因:
- 当前项目已经在走“场景 = 章节单元”的方向 - 当前项目已经在走“场景 = 章节单元”的方向
- 这层非常适合 AI 编排出第一版,再由百梦主补强记忆点 - 这层非常适合 AI 编排出第一版,再由陶泥儿主补强记忆点
## 5.9 叙事载体层 ## 5.9 叙事载体层
@@ -397,7 +397,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
- 场景遗物 - 场景遗物
- 怪物命名及其故事指向 - 怪物命名及其故事指向
百梦主主要修改: 陶泥儿主主要修改:
- 哪些载体最重要 - 哪些载体最重要
- 哪些载体和哪条线程绑定 - 哪些载体和哪条线程绑定
@@ -417,13 +417,13 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
原因: 原因:
- 这些内容适合 AI 批量铺量 - 这些内容适合 AI 批量铺量
- 百梦主只需要挑、改、锁定,不必从零起草 - 陶泥儿主只需要挑、改、锁定,不必从零起草
--- ---
## 6. 其余设定应交给系统托管 ## 6. 其余设定应交给系统托管
以下内容不建议默认暴露给百梦主编辑,应由系统根据前两层自动编译和维护。 以下内容不建议默认暴露给陶泥儿主编辑,应由系统根据前两层自动编译和维护。
## 6.1 题材与术语编译层 ## 6.1 题材与术语编译层
@@ -450,7 +450,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
原因: 原因:
- 百梦主要的是“故事线能对”,不是维护图数据库 - 陶泥儿主要的是“故事线能对”,不是维护图数据库
## 6.3 可见性和 prompt 裁剪层 ## 6.3 可见性和 prompt 裁剪层
@@ -465,7 +465,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
原因: 原因:
- 这层必须稳定、严格、自动化 - 这层必须稳定、严格、自动化
- 不适合依赖百梦主手动维护 - 不适合依赖陶泥儿主手动维护
## 6.4 运行时导演层 ## 6.4 运行时导演层
@@ -494,7 +494,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
说明: 说明:
- 百梦主可以编辑“任务卡”和“章节卡” - 陶泥儿主可以编辑“任务卡”和“章节卡”
- 但不应默认编辑底层 contract 结构 - 但不应默认编辑底层 contract 结构
## 6.6 数值与配置层 ## 6.6 数值与配置层
@@ -511,7 +511,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
说明: 说明:
- 百梦主可以给“偏向” - 陶泥儿主可以给“偏向”
- 系统负责编译成具体数值 - 系统负责编译成具体数值
## 6.7 QA 与一致性层 ## 6.7 QA 与一致性层
@@ -547,7 +547,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
| 主线 | 不强制首轮手写完整主线 | 幕结构、章节卡、高潮与 handoff | 章节状态编译 | | 主线 | 不强制首轮手写完整主线 | 幕结构、章节卡、高潮与 handoff | 章节状态编译 |
| 支线/角色线 | 不强制首轮手写完整矩阵 | 支线种子、角色线事件、阵营线分歧 | 任务 contract 编译 | | 支线/角色线 | 不强制首轮手写完整矩阵 | 支线种子、角色线事件、阵营线分歧 | 任务 contract 编译 |
| 场景章节 | 不强制首轮手写全量章节 | 场景章节卡、阶段内容、章节载体 | signal 与导演层 | | 场景章节 | 不强制首轮手写全量章节 | 场景章节卡、阶段内容、章节载体 | signal 与导演层 |
| 运行时结构 | 不建议百梦主接触 | 不建议默认编辑 | 可见性、导演、信号、编译、QA | | 运行时结构 | 不建议陶泥儿主接触 | 不建议默认编辑 | 可见性、导演、信号、编译、QA |
--- ---
@@ -555,7 +555,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
## 8.1 第一步:只填写最小必填集 ## 8.1 第一步:只填写最小必填集
百梦主只需要完成: 陶泥儿主只需要完成:
1. 世界一句话与核心幻想 1. 世界一句话与核心幻想
2. 玩家身份与开局困境 2. 玩家身份与开局困境
@@ -584,9 +584,9 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
这里的重点不是一次补满全世界,而是先形成一个像样的内容骨架。 这里的重点不是一次补满全世界,而是先形成一个像样的内容骨架。
## 8.3 第三步:百梦主只精修高价值卡片 ## 8.3 第三步:陶泥儿主只精修高价值卡片
建议默认优先让百梦主编辑这 4 类卡片: 建议默认优先让陶泥儿主编辑这 4 类卡片:
1. 关键角色 1. 关键角色
2. 核心冲突与线程 2. 核心冲突与线程
@@ -606,7 +606,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
- 任务包装 - 任务包装
- 文案变体 - 文案变体
## 8.5 第五步:百梦主按需进入高级模式 ## 8.5 第五步:陶泥儿主按需进入高级模式
高级模式只对愿意深挖的人开放: 高级模式只对愿意深挖的人开放:
@@ -665,7 +665,7 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
## 10.2 每张卡只保留自然语言输入 ## 10.2 每张卡只保留自然语言输入
不要强迫百梦主在首轮填写: 不要强迫陶泥儿主在首轮填写:
- tags - tags
- ids - ids
@@ -676,20 +676,20 @@ AI 生成后允许百梦主修改的,不应该是一堆技术型字段,而
更合理的做法是: 更合理的做法是:
-百梦主输入自然语言或选择直觉标签 -陶泥儿主输入自然语言或选择直觉标签
- 再由系统编译成结构化字段 - 再由系统编译成结构化字段
## 10.3 首轮生成后默认先看“精修建议” ## 10.3 首轮生成后默认先看“精修建议”
AI 初稿生成后,不应该把百梦主直接扔进一个大编辑器。 AI 初稿生成后,不应该把陶泥儿主直接扔进一个大编辑器。
更好的做法是先给出: 更好的做法是先给出:
1. 哪些卡片最值得改 1. 哪些卡片最值得改
2. 哪些内容已经比较稳定 2. 哪些内容已经比较稳定
3. 哪些内容仍然偏泛,需要百梦主补个性 3. 哪些内容仍然偏泛,需要陶泥儿主补个性
这样能明显提高百梦主的修改效率。 这样能明显提高陶泥儿主的修改效率。
## 10.4 移动端优先只保留高杠杆操作 ## 10.4 移动端优先只保留高杠杆操作
@@ -707,15 +707,15 @@ AI 初稿生成后,不应该把百梦主直接扔进一个大编辑器。
## 11. 最后结论 ## 11. 最后结论
如果目标是在自定义世界创作中真正平衡“降低门槛”和“提高作品质量”,最好的做法不是让百梦主填更多字段,也不是把一切都交给 AI。 如果目标是在自定义世界创作中真正平衡“降低门槛”和“提高作品质量”,最好的做法不是让陶泥儿主填更多字段,也不是把一切都交给 AI。
更合理的平衡是: 更合理的平衡是:
1. 百梦主必须手填最小但高杠杆的 6 张卡,掌握世界灵魂。 1. 陶泥儿主必须手填最小但高杠杆的 6 张卡,掌握世界灵魂。
2. AI 根据这 6 张卡生成一套可编辑的专业剧情初稿,负责把骨架展开成角色、地点、线程、章节和载体。 2. AI 根据这 6 张卡生成一套可编辑的专业剧情初稿,负责把骨架展开成角色、地点、线程、章节和载体。
3. 百梦主只精修最有价值的关键对象,锁定真正重要的内容。 3. 陶泥儿主只精修最有价值的关键对象,锁定真正重要的内容。
4. 其余运行结构、数值、可见性、任务编译和 QA 检查都交给系统托管。 4. 其余运行结构、数值、可见性、任务编译和 QA 检查都交给系统托管。
一句话收束: 一句话收束:
**百梦主负责决定“这个世界为什么值得被创作”AI 负责把它整理成可修改的策划初稿,系统负责把它稳定地跑成一个游戏世界。** **陶泥儿主负责决定“这个世界为什么值得被创作”AI 负责把它整理成可修改的策划初稿,系统负责把它稳定地跑成一个游戏世界。**

View File

@@ -10,7 +10,7 @@
- 基于“最小必填锚点 + AI 初稿卡片 + 系统托管层”的结构化创作方案 - 基于“最小必填锚点 + AI 初稿卡片 + 系统托管层”的结构化创作方案
2. 纯 Agent 式方向 2. 纯 Agent 式方向
- 以前台对话为唯一主交互,百梦主主要通过和 Agent 聊天来完成世界构建、角色塑造、剧情扩展和修改 - 以前台对话为唯一主交互,陶泥儿主主要通过和 Agent 聊天来完成世界构建、角色塑造、剧情扩展和修改
文档需要回答 3 个问题: 文档需要回答 3 个问题:
@@ -34,7 +34,7 @@
当前方案的核心是: 当前方案的核心是:
1. 百梦主手填最小高杠杆锚点 1. 陶泥儿主手填最小高杠杆锚点
2. AI 生成一批可编辑的剧情策划初稿卡片 2. AI 生成一批可编辑的剧情策划初稿卡片
3. 系统把内容编译成运行时结构 3. 系统把内容编译成运行时结构
@@ -42,7 +42,7 @@
**结构化工作台 + AI 协作生成。** **结构化工作台 + AI 协作生成。**
百梦主的主要行为是: 陶泥儿主的主要行为是:
1. 填写关键卡片 1. 填写关键卡片
2. 修改关键角色、地点、势力、章节等内容卡 2. 修改关键角色、地点、势力、章节等内容卡
@@ -53,9 +53,9 @@
纯 Agent 式不是指“系统内部没有结构”,而是指: 纯 Agent 式不是指“系统内部没有结构”,而是指:
**百梦主前台几乎不需要面对表单和卡片编辑器,主要通过自然语言对话来完成创作。** **陶泥儿主前台几乎不需要面对表单和卡片编辑器,主要通过自然语言对话来完成创作。**
百梦主的主要行为变成: 陶泥儿主的主要行为变成:
1. 用自然语言描述世界想法 1. 用自然语言描述世界想法
2. 回答 Agent 的追问 2. 回答 Agent 的追问
@@ -77,7 +77,7 @@
1. 前台用户主要通过什么方式思考和输入? 1. 前台用户主要通过什么方式思考和输入?
2. 后台系统是否仍然有稳定的世界模型和编译层? 2. 后台系统是否仍然有稳定的世界模型和编译层?
3. 百梦主是否还能看见摘要、锁定内容和修改范围? 3. 陶泥儿主是否还能看见摘要、锁定内容和修改范围?
对当前项目来说,真正危险的不是“转成聊天”,而是: 对当前项目来说,真正危险的不是“转成聊天”,而是:
@@ -93,11 +93,11 @@
它更擅长: 它更擅长:
1. 帮不擅长表单和结构思考的百梦主起步 1. 帮不擅长表单和结构思考的陶泥儿主起步
2.百梦主思路模糊时做追问和陪创作 2.陶泥儿主思路模糊时做追问和陪创作
3. 把“我要做一个世界”变成一次自然聊天 3. 把“我要做一个世界”变成一次自然聊天
4. 动态决定追问深度,而不是一上来摆很多字段 4. 动态决定追问深度,而不是一上来摆很多字段
5.百梦主感觉自己是在和一个懂 RPG 的剧情搭档共创 5.陶泥儿主感觉自己是在和一个懂 RPG 的剧情搭档共创
## 2.2 纯 Agent 式的主要问题 ## 2.2 纯 Agent 式的主要问题
@@ -110,7 +110,7 @@
1. 聊天很多,但世界状态越来越难总览 1. 聊天很多,但世界状态越来越难总览
2. 角色、地点、势力和章节信息散落在多轮消息里 2. 角色、地点、势力和章节信息散落在多轮消息里
3. 锁定范围不清,重生成容易误伤已有内容 3. 锁定范围不清,重生成容易误伤已有内容
4. Agent 很容易“替百梦主决定太多” 4. Agent 很容易“替陶泥儿主决定太多”
5. 长会话越来越贵,越来越慢,也越来越容易漂移 5. 长会话越来越贵,越来越慢,也越来越容易漂移
## 2.3 对当前项目的判断 ## 2.3 对当前项目的判断
@@ -197,7 +197,7 @@
纯 Agent 式更弱的地方在于: 纯 Agent 式更弱的地方在于:
1. 世界模型隐藏得太深时,百梦主会失去整体掌控感 1. 世界模型隐藏得太深时,陶泥儿主会失去整体掌控感
2. 多轮对话后,已确定内容不容易被清晰回看 2. 多轮对话后,已确定内容不容易被清晰回看
3. 局部重做和精确编辑边界会变模糊 3. 局部重做和精确编辑边界会变模糊
4. Agent 容易过度代写、过度主导 4. Agent 容易过度代写、过度主导
@@ -223,7 +223,7 @@
因为这些环节的关键问题不是“字段如何摆放”,而是: 因为这些环节的关键问题不是“字段如何摆放”,而是:
**百梦主有没有被真正引导出自己想做的世界。** **陶泥儿主有没有被真正引导出自己想做的世界。**
## 4.2 不值得直接转成纯聊天黑箱的部分 ## 4.2 不值得直接转成纯聊天黑箱的部分
@@ -261,8 +261,8 @@
即使转成纯 Agent 式,也仍然要保留这三层: 即使转成纯 Agent 式,也仍然要保留这三层:
1. 百梦主必须确认的高杠杆锚点 1. 陶泥儿主必须确认的高杠杆锚点
2. AI 生成但允许百梦主修改的策划初稿层 2. AI 生成但允许陶泥儿主修改的策划初稿层
3. 系统托管的运行时编译层 3. 系统托管的运行时编译层
变化的只是: 变化的只是:
@@ -339,7 +339,7 @@
2. 会阶段性总结 2. 会阶段性总结
3. 会把聊天结果沉淀成结构化世界状态 3. 会把聊天结果沉淀成结构化世界状态
4. 会提醒风险和冲突 4. 会提醒风险和冲突
5. 会在百梦主要求时进行局部重写和定向扩展 5. 会在陶泥儿主要求时进行局部重写和定向扩展
## 6.2 正确理解 ## 6.2 正确理解
@@ -349,7 +349,7 @@
也就是说: 也就是说:
1. 百梦主看到的是对话 1. 陶泥儿主看到的是对话
2. 系统内部维护的是世界模型、锁定状态、摘要和编译结果 2. 系统内部维护的是世界模型、锁定状态、摘要和编译结果
--- ---
@@ -389,7 +389,7 @@ Agent 首轮不应该直接铺满全世界,而应该给出一份简明底稿
2. 建议内容 2. 建议内容
3. 待确认内容 3. 待确认内容
## 7.3 阶段 C百梦主锁定锚点 ## 7.3 阶段 C陶泥儿主锁定锚点
在纯 Agent 模式里,锁定行为必须被显式支持。 在纯 Agent 模式里,锁定行为必须被显式支持。
@@ -455,7 +455,7 @@ Agent 不应该每轮都继续扩全局,而应该支持“单对象工作模
| 结构 | 作用 | | 结构 | 作用 |
| --- | --- | | --- | --- |
| `creatorIntentProfile` | 当前百梦主最初和最新的创作意图 | | `creatorIntentProfile` | 当前陶泥儿主最初和最新的创作意图 |
| `lockedAnchors` | 已确认不可自动改写的内容 | | `lockedAnchors` | 已确认不可自动改写的内容 |
| `worldDraftSnapshot` | 当前世界底稿快照 | | `worldDraftSnapshot` | 当前世界底稿快照 |
| `editableDraftCards` | 角色、地点、势力、章节等可编辑初稿 | | `editableDraftCards` | 角色、地点、势力、章节等可编辑初稿 |
@@ -530,7 +530,7 @@ Agent 不能像问卷系统,也不能一次追问太多。
1. 一次最多追问 `1~3` 个问题 1. 一次最多追问 `1~3` 个问题
2. 问题必须是当前最缺的高杠杆信息 2. 问题必须是当前最缺的高杠杆信息
3. 每次追问都给默认建议方向 3. 每次追问都给默认建议方向
4. 如果百梦主不想细答,允许 Agent 先代补一个版本再确认 4. 如果陶泥儿主不想细答,允许 Agent 先代补一个版本再确认
这样才能保持“像聊天”,而不是“像客服表单”。 这样才能保持“像聊天”,而不是“像客服表单”。
@@ -614,14 +614,14 @@ Agent 应能识别这些常见修改类型:
3. 锁定内容固定展示 3. 锁定内容固定展示
4. 提供“当前世界圣经”入口 4. 提供“当前世界圣经”入口
## 11.2 风险 2Agent 过度代写,百梦主失去作品归属感 ## 11.2 风险 2Agent 过度代写,陶泥儿主失去作品归属感
防护方式: 防护方式:
1. 高杠杆锚点必须要求确认 1. 高杠杆锚点必须要求确认
2. 重要改动前先说“我准备改什么” 2. 重要改动前先说“我准备改什么”
3. 默认优先给多个候选,而不是直接盖写 3. 默认优先给多个候选,而不是直接盖写
4. 允许百梦主随时回退到旧版本 4. 允许陶泥儿主随时回退到旧版本
## 11.3 风险 3局部修改带出全局漂移 ## 11.3 风险 3局部修改带出全局漂移

View File

@@ -37,8 +37,8 @@
- 不能先删旧字段,再补新结构。 - 不能先删旧字段,再补新结构。
- 必须先补新设定层,再逐步迁读,最后再让旧模板字段退化成兼容层。 - 必须先补新设定层,再逐步迁读,最后再让旧模板字段退化成兼容层。
4. 不能增加百梦主负担 4. 不能增加陶泥儿主负担
- 这次不是让百梦主多填一堆底层 schema。 - 这次不是让陶泥儿主多填一堆底层 schema。
- 这些设定仍然应由 AI / 系统编译出来,只是所有权从模板世界转移到自定义世界自己。 - 这些设定仍然应由 AI / 系统编译出来,只是所有权从模板世界转移到自定义世界自己。
--- ---

View File

@@ -102,9 +102,9 @@
这不是真正跨题材,只是换了名字。 这不是真正跨题材,只是换了名字。
## 3.3 不能让百梦主承担更多底层配置工作 ## 3.3 不能让陶泥儿主承担更多底层配置工作
这次优化不是让百梦主额外填写: 这次优化不是让陶泥儿主额外填写:
- 怪物模板表 - 怪物模板表
- 场景参考池 - 场景参考池

View File

@@ -349,7 +349,7 @@ export interface ChapterProgressionPlan {
} }
``` ```
建议作为后端运行时编译结果缓存,不作为百梦主直接编辑字段。 建议作为后端运行时编译结果缓存,不作为陶泥儿主直接编辑字段。
## 3.7 章节经验记账 ## 3.7 章节经验记账
@@ -636,7 +636,7 @@ chapterXpBudget =
3. 非主角色友方 NPC 3. 非主角色友方 NPC
- `support``ambient` - `support``ambient`
如需修正,再允许章节蓝图加可选 override但不要求百梦主每次手填。 如需修正,再允许章节蓝图加可选 override但不要求陶泥儿主每次手填。
## 7.2 等级锚点 ## 7.2 等级锚点

View File

@@ -22,6 +22,7 @@
5. 已发布卡片在描述下方显示三项公开指标:游玩数、改造数、点赞数。 5. 已发布卡片在描述下方显示三项公开指标:游玩数、改造数、点赞数。
6. 已发布卡片右上角显示分享 icon点击后复制作品分享文案不触发卡片打开。 6. 已发布卡片右上角显示分享 icon点击后复制作品分享文案不触发卡片打开。
7. 草稿卡片右上角继续显示删除 icon点击删除不触发卡片打开。 7. 草稿卡片右上角继续显示删除 icon点击删除不触发卡片打开。
8. 卡片不显示最后修改时间;`updatedAt` 只用于作品列表排序。
## 公开指标重点展示补充 ## 公开指标重点展示补充
@@ -30,7 +31,9 @@
3. 用户每次进入创作页时,前端读取上一次进入该页面缓存的公开指标快照;当已发布作品卡片滑动进入视口后,数字从缓存值增长到本次接口返回的最新值。 3. 用户每次进入创作页时,前端读取上一次进入该页面缓存的公开指标快照;当已发布作品卡片滑动进入视口后,数字从缓存值增长到本次接口返回的最新值。
4. 若最新值高于缓存值,动画完成后在对应指标右下角展示红色向上箭头和本次上涨的具体数值,字号低于主数字,避免抢占主信息层级。 4. 若最新值高于缓存值,动画完成后在对应指标右下角展示红色向上箭头和本次上涨的具体数值,字号低于主数字,避免抢占主信息层级。
5. 若没有缓存值、缓存值不低于最新值或作品仍是草稿,则直接显示最新值,不展示上涨标记。 5. 若没有缓存值、缓存值不低于最新值或作品仍是草稿,则直接显示最新值,不展示上涨标记。
6. 每张作品卡片继续使用作品封面作为整卡背景,封面需要有透明度和渐变遮罩,确保标题、描述和指标在亮色与暗色主题下都清晰可读 6. 每张作品卡片继续使用作品封面作为整卡背景,封面保持主视觉可见;遮罩只用于保证标题、描述和指标可读,不能把封面洗成普通面板底色
7. 作品列表按 `updatedAt` 倒序排列;前端排序需要兼容 ISO 时间和 Rust 后端常用的 `seconds.microsZ` 时间文本。
8. 若玩法摘要缺少 `coverImageSrc`,允许从同一作品的正式关卡图、背景图或素材图里取第一张可用图片作为卡片背景兜底。
## 移动端布局规则 ## 移动端布局规则

View File

@@ -96,7 +96,7 @@
- 同时开放短信与密码登录时,面板顶部展示两个居中的文字页签,当前页签使用深色字重和短下划线强调。 - 同时开放短信与密码登录时,面板顶部展示两个居中的文字页签,当前页签使用深色字重和短下划线强调。
- 只渲染当前页签对应的输入区;切换页签不弹出新面板,不展示二维码入口。 - 只渲染当前页签对应的输入区;切换页签不弹出新面板,不展示二维码入口。
- `短信登录` 页签包含手机号、验证码、获取验证码和主按钮。 - `短信登录` 页签包含手机号、验证码、获取验证码和主按钮。
- `密码登录` 页签只包含手机号、密码、主按钮和忘记密码入口;不支持邮箱、用户名或百梦号。 - `密码登录` 页签只包含手机号、密码、主按钮和忘记密码入口;不支持邮箱、用户名或陶泥号。
- 密码登录只是手机号验证码登录的补充方式:只有已登录并设置过密码的手机号账号才能使用,不能在密码页签创建账号。 - 密码登录只是手机号验证码登录的补充方式:只有已登录并设置过密码的手机号账号才能使用,不能在密码页签创建账号。
- `密码登录` 主按钮固定为 `登录`,不得使用 `注册/登录` - `密码登录` 主按钮固定为 `登录`,不得使用 `注册/登录`
- 未开放某个登录方式时不展示对应页签,避免用户进入不可用表单。 - 未开放某个登录方式时不展示对应页签,避免用户进入不可用表单。

View File

@@ -11,7 +11,7 @@
3. 原“排行”页内容并入“发现”页的子 Tab 中,不再作为一级主 Tab 独立展示。 3. 原“排行”页内容并入“发现”页的子 Tab 中,不再作为一级主 Tab 独立展示。
4. 创作页只保留新建创作入口;原创作页作品列表拆到一级“草稿” Tab替换原“存档” Tab。 4. 创作页只保留新建创作入口;原创作页作品列表拆到一级“草稿” Tab替换原“存档” Tab。
5. 原“存档”列表结构并入“我的”页面的“玩过”列表弹层,作为每个已玩作品的可继续存档入口。 5. 原“存档”列表结构并入“我的”页面的“玩过”列表弹层,作为每个已玩作品的可继续存档入口。
6. 移动端推荐页与底部 Tab 栏参考用户给定样式,使用大画面推荐流、顶部品牌/通知、悬浮胶囊底部导航;保留当前平台已有明暗两套主题色 token。 6. 移动端推荐页与底部 Tab 栏参考用户给定样式,使用大画面推荐流、顶部品牌悬浮胶囊底部导航;右上角不保留通知按钮,账号相关入口统一进入“我的”和账号面板;保留当前平台已有明暗两套主题色 token。
## 2. 状态映射 ## 2. 状态映射
@@ -68,6 +68,9 @@
- 默认显示全部作品列表,保留草稿/已发布筛选。 - 默认显示全部作品列表,保留草稿/已发布筛选。
- 入口、删除、分享、领取拼图激励等行为全部复用现有 `CustomWorldCreationHub` 的作品卡逻辑。 - 入口、删除、分享、领取拼图激励等行为全部复用现有 `CustomWorldCreationHub` 的作品卡逻辑。
- 一级底部 Tab 文案为“草稿”,内部仍可按草稿与已发布筛选。 - 一级底部 Tab 文案为“草稿”,内部仍可按草稿与已发布筛选。
- 作品列表必须按最后修改时间倒序排列;排序使用后端 `updatedAt`,前端需要兼容 ISO 字符串和 `seconds.microsZ` 两种时间文本。
- 每张作品卡以作品封面图铺满整卡背景,并叠加遮罩保证标题和描述可读;遮罩不能把封面洗成普通面板底色。缺 `coverImageSrc` 但同一作品已有正式关卡图、背景图或素材图时,优先用这些真实作品图兜底,再使用现有兜底底图。
- 草稿页卡片不展示“最后修改时间”“更新于”或原始 `updatedAt` 文本,时间只参与排序。
## 6. 我的页玩过列表 ## 6. 我的页玩过列表
@@ -124,3 +127,5 @@
- 草稿作品卡在生成中展示“生成中”状态标记;新生成完成且用户尚未查看的草稿在卡片右上角展示红点。 - 草稿作品卡在生成中展示“生成中”状态标记;新生成完成且用户尚未查看的草稿在卡片右上角展示红点。
- 底部一级“草稿”Tab 在存在未查看新完成草稿时展示红点用户点击查看带红点的作品后该作品红点消失。若草稿页已无任何带红点作品底部“草稿”Tab 红点同步消失。 - 底部一级“草稿”Tab 在存在未查看新完成草稿时展示红点用户点击查看带红点的作品后该作品红点消失。若草稿页已无任何带红点作品底部“草稿”Tab 红点同步消失。
- 生成完成时如果用户仍停留在对应生成过程页,可自动进入结果页;如果用户已经回到创作中心或其它功能页,不打断当前操作。 - 生成完成时如果用户仍停留在对应生成过程页,可自动进入结果页;如果用户已经回到创作中心或其它功能页,不打断当前操作。
- 创作 Tab 的模板入口只允许被模板自身的开放状态禁用;某个草稿后台生成中时,不得用该玩法的 busy 状态禁用其它模板入口、同模板再次创建入口或阻止用户继续创建新作品。
- 同模板再次点击生成时必须创建新的草稿生成任务,不得因为当前玩法已有后台生成 session 就跳回上一条草稿的生成过程页;查看上一条生成进度只能从草稿 Tab 的对应作品卡进入。

View File

@@ -59,8 +59,8 @@
### 3.2 排版 ### 3.2 排版
- 平台层正文、按钮、说明、功能标签统一使用非像素字体 - 平台层正文、按钮、说明、功能标签统一使用非像素字体
- 左上角 `百梦 / GENARRATIVE` 品牌字标允许单独做成像素化 logo - 左上角 `陶泥儿 / GENARRATIVE` 品牌字标允许单独做成像素化 logo
- `GENARRATIVE``百梦` 都优先直接使用游戏内同款 `Fusion Pixel` - `GENARRATIVE``陶泥儿` 都优先直接使用游戏内同款 `Fusion Pixel`
- 品牌字标默认保持正常像素字观感,禁止再叠双层粗阴影或手动加粗到影响识别 - 品牌字标默认保持正常像素字观感,禁止再叠双层粗阴影或手动加粗到影响识别
- 品牌字标直接使用字体文件内原字形,不额外做运行时描字、轮廓拼字或伪粗体处理 - 品牌字标直接使用字体文件内原字形,不额外做运行时描字、轮廓拼字或伪粗体处理
- 主标题保留明显层级,但不再做像素描边效果 - 主标题保留明显层级,但不再做像素描边效果

View File

@@ -5,7 +5,8 @@
## 文档列表 ## 文档列表
- [CHILD_MOTION_DEMO_WARMUP_LEVEL_DESIGN_2026-05-09.md](./CHILD_MOTION_DEMO_WARMUP_LEVEL_DESIGN_2026-05-09.md)4-8 岁儿童动作识别互动玩法 Demo 固定热身关的横屏体验流程、识别目标、表现需求与待确认事项。 - [CHILD_MOTION_DEMO_WARMUP_LEVEL_DESIGN_2026-05-09.md](./CHILD_MOTION_DEMO_WARMUP_LEVEL_DESIGN_2026-05-09.md)4-8 岁儿童动作识别互动玩法 Demo 固定热身关的横屏体验流程、识别目标、表现需求与待确认事项。
- [CUSTOM_WORLD_CREATOR_INPUT_AND_AI_BOUNDARY_DESIGN_2026-04-06.md](./CUSTOM_WORLD_CREATOR_INPUT_AND_AI_BOUNDARY_DESIGN_2026-04-06.md)自定义世界里百梦主输入与 AI 分工边界设计 - [TAONIER_BRAND_LOGO_CONCEPTS_2026-05-13.md](./TAONIER_BRAND_LOGO_CONCEPTS_2026-05-13.md)候选产品名“陶泥儿”的品牌定位归纳、gpt-image-2 Logo 概念图和主标选择建议
- [CUSTOM_WORLD_CREATOR_INPUT_AND_AI_BOUNDARY_DESIGN_2026-04-06.md](./CUSTOM_WORLD_CREATOR_INPUT_AND_AI_BOUNDARY_DESIGN_2026-04-06.md):自定义世界里陶泥儿主输入与 AI 分工边界设计。
- [CUSTOM_WORLD_CREATOR_MANUAL_AI_SYSTEM_BALANCE_DESIGN_2026-04-12.md](./CUSTOM_WORLD_CREATOR_MANUAL_AI_SYSTEM_BALANCE_DESIGN_2026-04-12.md):自定义世界创作里“手填锚点 / AI 可改初稿 / 系统托管层”的平衡设计。 - [CUSTOM_WORLD_CREATOR_MANUAL_AI_SYSTEM_BALANCE_DESIGN_2026-04-12.md](./CUSTOM_WORLD_CREATOR_MANUAL_AI_SYSTEM_BALANCE_DESIGN_2026-04-12.md):自定义世界创作里“手填锚点 / AI 可改初稿 / 系统托管层”的平衡设计。
- [CUSTOM_WORLD_CREATOR_PURE_AGENT_COMPARISON_AND_CONVERSION_DESIGN_2026-04-12.md](./CUSTOM_WORLD_CREATOR_PURE_AGENT_COMPARISON_AND_CONVERSION_DESIGN_2026-04-12.md):纯 Agent 式创作工具与结构化工作台方案的优缺点对比,以及转型设计。 - [CUSTOM_WORLD_CREATOR_PURE_AGENT_COMPARISON_AND_CONVERSION_DESIGN_2026-04-12.md](./CUSTOM_WORLD_CREATOR_PURE_AGENT_COMPARISON_AND_CONVERSION_DESIGN_2026-04-12.md):纯 Agent 式创作工具与结构化工作台方案的优缺点对比,以及转型设计。
- [CUSTOM_WORLD_TEMPLATE_DECOUPLING_AND_CROSS_GENRE_GENERALIZATION_DESIGN_2026-04-08.md](./CUSTOM_WORLD_TEMPLATE_DECOUPLING_AND_CROSS_GENRE_GENERALIZATION_DESIGN_2026-04-08.md):把自定义世界从武侠/仙侠模板依赖迁到跨题材通用设定层的优化设计。 - [CUSTOM_WORLD_TEMPLATE_DECOUPLING_AND_CROSS_GENRE_GENERALIZATION_DESIGN_2026-04-08.md](./CUSTOM_WORLD_TEMPLATE_DECOUPLING_AND_CROSS_GENRE_GENERALIZATION_DESIGN_2026-04-08.md):把自定义世界从武侠/仙侠模板依赖迁到跨题材通用设定层的优化设计。
@@ -18,7 +19,7 @@
- [PLATFORM_CATEGORY_AND_CREATE_TAB_DESIGN_2026-04-24.md](./PLATFORM_CATEGORY_AND_CREATE_TAB_DESIGN_2026-04-24.md):平台入口新增分类 Tab、登录态导航裁剪与创作 Tab 视觉强化设计。 - [PLATFORM_CATEGORY_AND_CREATE_TAB_DESIGN_2026-04-24.md](./PLATFORM_CATEGORY_AND_CREATE_TAB_DESIGN_2026-04-24.md):平台入口新增分类 Tab、登录态导航裁剪与创作 Tab 视觉强化设计。
- [PLATFORM_BIG_FISH_ENTRY_HIDE_2026-04-28.md](./PLATFORM_BIG_FISH_ENTRY_HIDE_2026-04-28.md):平台入口暂时隐藏大鱼吃小鱼创作卡片,但保留现有玩法链路。 - [PLATFORM_BIG_FISH_ENTRY_HIDE_2026-04-28.md](./PLATFORM_BIG_FISH_ENTRY_HIDE_2026-04-28.md):平台入口暂时隐藏大鱼吃小鱼创作卡片,但保留现有玩法链路。
- [UNIFIED_MODAL_WINDOW_DESIGN_2026-04-25.md](./UNIFIED_MODAL_WINDOW_DESIGN_2026-04-25.md):统一平台风与 RPG 像素风模态窗口外壳、交互边界和迁移顺序。 - [UNIFIED_MODAL_WINDOW_DESIGN_2026-04-25.md](./UNIFIED_MODAL_WINDOW_DESIGN_2026-04-25.md):统一平台风与 RPG 像素风模态窗口外壳、交互边界和迁移顺序。
- [BAIMENG_EXPO_ROLLUP_BANNER_DESIGN_2026-05-07.md](./BAIMENG_EXPO_ROLLUP_BANNER_DESIGN_2026-05-07.md)百梦线下展会易拉宝广告展板的文案层级、视觉方向与 gpt-image-2 生成记录。 - [BAIMENG_EXPO_ROLLUP_BANNER_DESIGN_2026-05-07.md](./BAIMENG_EXPO_ROLLUP_BANNER_DESIGN_2026-05-07.md)陶泥儿线下展会易拉宝广告展板的文案层级、视觉方向与 gpt-image-2 生成记录。
- [AI_NATIVE_RUNTIME_ITEM_SYSTEM_REDESIGN_2026-04-02.md](./AI_NATIVE_RUNTIME_ITEM_SYSTEM_REDESIGN_2026-04-02.md):运行时物品生成系统重设计。 - [AI_NATIVE_RUNTIME_ITEM_SYSTEM_REDESIGN_2026-04-02.md](./AI_NATIVE_RUNTIME_ITEM_SYSTEM_REDESIGN_2026-04-02.md):运行时物品生成系统重设计。
- [LEVEL_PROGRESS_AND_CHAPTER_NPC_AUTO_SCALING_DESIGN_2026-04-20.md](./LEVEL_PROGRESS_AND_CHAPTER_NPC_AUTO_SCALING_DESIGN_2026-04-20.md):等级成长、章节经验节奏与 NPC 自动定级设计。 - [LEVEL_PROGRESS_AND_CHAPTER_NPC_AUTO_SCALING_DESIGN_2026-04-20.md](./LEVEL_PROGRESS_AND_CHAPTER_NPC_AUTO_SCALING_DESIGN_2026-04-20.md):等级成长、章节经验节奏与 NPC 自动定级设计。
- [RPG_NARRATIVE_PLANNING_FULL_PIPELINE_WORKFLOW_2026-04-12.md](./RPG_NARRATIVE_PLANNING_FULL_PIPELINE_WORKFLOW_2026-04-12.md):专业剧情策划构建 RPG 游戏全剧情的工作流程与交付模板。 - [RPG_NARRATIVE_PLANNING_FULL_PIPELINE_WORKFLOW_2026-04-12.md](./RPG_NARRATIVE_PLANNING_FULL_PIPELINE_WORKFLOW_2026-04-12.md):专业剧情策划构建 RPG 游戏全剧情的工作流程与交付模板。
@@ -33,8 +34,8 @@
- 做物品、Build、锻造相关需求时先看前两份。 - 做物品、Build、锻造相关需求时先看前两份。
- 做 RPG 全剧情规划、主支线矩阵、角色线、场景章节与剧情交付模板时,先看新增的全剧情策划流程。 - 做 RPG 全剧情规划、主支线矩阵、角色线、场景章节与剧情交付模板时,先看新增的全剧情策划流程。
- 做自定义世界创作工作台、百梦主输入边界、AI 分工设计时,先看第一份。 - 做自定义世界创作工作台、陶泥儿主输入边界、AI 分工设计时,先看第一份。
- 做“哪些内容必须让百梦主手填、哪些适合 AI 先生成再改、哪些必须系统托管”这类分层设计时,优先看新增的输入平衡设计稿。 - 做“哪些内容必须让陶泥儿主手填、哪些适合 AI 先生成再改、哪些必须系统托管”这类分层设计时,优先看新增的输入平衡设计稿。
- 做“是否应该转成纯 Agent 式创作工具、转了之后前后台各该怎么收口”这类产品方向评估时,优先看新增的纯 Agent 对比与转型设计稿。 - 做“是否应该转成纯 Agent 式创作工具、转了之后前后台各该怎么收口”这类产品方向评估时,优先看新增的纯 Agent 对比与转型设计稿。
- 做自定义世界去模板依赖、跨题材泛化、兼容迁移设计时,优先看新增的去模板化优化设计稿。 - 做自定义世界去模板依赖、跨题材泛化、兼容迁移设计时,优先看新增的去模板化优化设计稿。
- 做“模板依赖如何真正变成自定义世界自有设定层”的具体迁移方案时,优先看新增的自有设定层优化方案。 - 做“模板依赖如何真正变成自定义世界自有设定层”的具体迁移方案时,优先看新增的自有设定层优化方案。

View File

@@ -0,0 +1,423 @@
# 陶泥儿品牌 Logo 概念稿
> 本稿是围绕候选产品名“陶泥儿”的品牌视觉探索,不替代当前已冻结的“百梦”正式命名口径。若后续确认更名,需要另起产品命名、前后端文案和商标检索落地方案。
## 1. 品牌定位归纳
“陶泥儿”适合承接的不是传统陶艺或儿童黏土,而是“把灵感塑形成可玩内容”的 AI 创作平台隐喻。
核心关键词:
- 精品:作品不是随手糊出来,而是经过 AI 辅助打磨、可被消费和传播的轻精品内容。
- UGC用户是主要造物者平台降低创作门槛。
- 创作:从一句脑洞、一个梗、一张图,生成小游戏、互动作品或可分享内容。
- 裂变与梗:名字要支持“开捏”“捏个梗”“捏个小游戏”这类用户语言。
- 轻度休闲:体验应松弛、即时、好玩,不走硬核生产工具气质。
- AIAI 是塑形能力,不是冷冰冰的技术标签。
推荐品牌主张:
```text
把脑洞捏成小游戏
```
备选表达:
```text
捏个脑洞,马上开玩
AI 开捏,人人会创作
随手造梗,随心开玩
```
## 2. 生成原则
本轮使用仓库 GPT-image-2 / VectorEngine 工作流生成 Logo 概念图,生成时刻意要求“无文字 Logo 图标”。
原因:
- AI 生图直接生成中文品牌字容易出现笔画错误,不适合作为正式字标。
- 当前阶段更适合先确定图形符号方向,再由设计师或前端继续做矢量化、字标搭配和多尺寸适配。
- 图标需要优先服务 App icon、平台左上角品牌、分享卡片和加载页而不是一次性海报图。
生成文件:
```text
public/branding/taonier-logo-v3-concepts/
├─ taonier-logo-v3-contact-sheet.png
├─ taonier-v3-finger-spark.png
├─ taonier-v3-seed-pop.png
├─ taonier-v3-magic-dot.png
├─ taonier-v3-work-gem.png
└─ taonier-v3-soft-t.png
public/branding/taonier-logo-magic-dot-concepts/
├─ taonier-logo-magic-dot-contact-sheet.png
├─ taonier-magic-dot-orbit.png
├─ taonier-magic-dot-seal.png
├─ taonier-magic-dot-squish.png
├─ taonier-magic-dot-mold.png
└─ taonier-magic-dot-bloom.png
public/branding/taonier-logo-flat-concepts/
├─ taonier-logo-flat-contact-sheet.png
├─ taonier-flat-play-clay.png
├─ taonier-flat-spark-clay.png
├─ taonier-flat-meme-smile.png
├─ taonier-flat-loop-mold.png
└─ taonier-flat-seal-blocks.png
public/branding/taonier-logo-concepts/
├─ taonier-logo-contact-sheet.png
├─ taonier-clay-spark.png
├─ taonier-play-mold.png
├─ taonier-meme-bubble.png
├─ taonier-creation-loop.png
└─ taonier-premium-seal.png
```
生成脚本:
```text
scripts/generate-taonier-logo-concepts.mjs
```
## 3. V3-03 一捏成型延展
这一组专门沿 V3 “一捏成型”继续打磨。目标是保留“两个软形触点 + 中央作品核”的成型瞬间,同时降低括号感、碰撞特效感和功能按钮感。
![陶泥儿 Logo 一捏成型延展总览](../../public/branding/taonier-logo-magic-dot-concepts/taonier-logo-magic-dot-contact-sheet.png)
### 3.1 捏合星核
![捏合星核](../../public/branding/taonier-logo-magic-dot-concepts/taonier-magic-dot-orbit.png)
定位:一捏成型方向的主标首选。
这个方向最稳地保留了“左右合拢、中央成型”的核心动作,中心青绿色星核形成了明确焦点,整体比原 V3-03 更完整,也没有明显播放器、聊天或表情联想。
优点:
- 结构清楚,第一眼能看出“合拢生成”。
- 元素少,小尺寸适配潜力好。
- 中央星核可以做加载、生成成功、发布完成等动效延展。
风险:
- 左右软形仍有一点括号感,后续矢量化可把外轮廓做得更不对称、更像被捏塑的软泥。
建议用途:主 Logo 备选首选、AI 生成按钮、启动动效核心符号。
### 3.2 成型印记
![成型印记](../../public/branding/taonier-logo-magic-dot-concepts/taonier-magic-dot-seal.png)
定位:完整主标感最强的延展方向。
这个方向把左右触点收成一个更完整的软形图腾,减少了“两个括号”的割裂感。视觉上更像独立品牌符号,但也因此少了一点“捏合动作”的即时感。
建议用途:主 Logo 强备选;若选择它,后续应去掉背景底色并强化中心负形星点。
### 3.3 软泥合拍
![软泥合拍](../../public/branding/taonier-logo-magic-dot-concepts/taonier-magic-dot-squish.png)
定位:轻松、年轻、动效友好。
这个方向的上下软形更活泼,适合表达“啪嗒一下成型”。但静态 Logo 中的黄色星点和短线略像特效贴纸,主标使用前需要继续简化。
建议用途:生成中动效、运营图、互动反馈,不建议直接定为主 Logo。
### 3.4 灵感模口
![灵感模口](../../public/branding/taonier-logo-magic-dot-concepts/taonier-magic-dot-mold.png)
定位:最有“模口 / 造物容器”意味。
这个方向图形独特,和“从软泥模口里生成作品”的隐喻贴合。但外形复杂度比 01、02 更高,边缘细节在小尺寸下可能损失。
建议用途:主 Logo 备选探索,适合继续做专业矢量简化。
### 3.5 捏开灵感
![捏开灵感](../../public/branding/taonier-logo-magic-dot-concepts/taonier-magic-dot-bloom.png)
定位:温和、包裹、生成容器。
这个方向亲和、平衡,但整体像眼睛 / 容器 / 开合结构,陶泥儿的“捏”动作弱一些。
建议用途AI 生成入口、等待态、创作容器辅助图形。
## 4. V3 抽象主标候选
V3 根据评审反馈重新避开了五个问题:播放三角、褐色陶土主色、聊天气泡 / 表情包、循环符号,以及过多碎元素。方向转为更抽象、更亮眼、更像长期主 Logo 的符号。
![陶泥儿 Logo V3 概念总览](../../public/branding/taonier-logo-v3-concepts/taonier-logo-v3-contact-sheet.png)
### 4.1 灵感捏痕
![灵感捏痕](../../public/branding/taonier-logo-v3-concepts/taonier-v3-finger-spark.png)
定位:主 Logo 首选。
这个方向用醒目的珊瑚红软形、指纹捏痕和星点负形建立记忆点。它不再依赖“陶泥的褐色”,而是用“被捏过的痕迹”表达陶泥儿的核心动作:用户把脑洞捏成作品。
优点:
- 第一眼足够醒目,远离旧版褐色和播放器感。
- 指纹捏痕有独特性,能承接“人人创作”和“亲手塑形”。
- 元素少,适合继续矢量化和小尺寸适配。
风险:
- 指纹弧线后续需要进一步简化,避免在 24px 以下变糊。
- 星点比例要克制,避免变成普通灵感图标。
建议用途:主 Logo、App icon、平台顶栏、启动页、生成按钮。
### 4.2 脑洞种子
![脑洞种子](../../public/branding/taonier-logo-v3-concepts/taonier-v3-seed-pop.png)
定位:创意生长与新手友好。
这个方向从“灵感发芽”切入,比陶泥更偏创造生命力。它亲和、可爱,但容易让用户联想到教育、植物、儿童启蒙或种植类产品。
建议用途:新手引导、创作孵化、儿童 / 寓教于乐支线,不建议作为主 Logo。
### 4.3 一捏成型
![一捏成型](../../public/branding/taonier-logo-v3-concepts/taonier-v3-magic-dot.png)
定位AI 把灵感合成为作品的瞬间。
这个方向很简洁,用左右两个软形触点和中心星点表达“捏合”。它避开了播放器和聊天气泡,也能做动效,但静态图形目前稍像碰撞特效或括号,需要继续重绘增强独特轮廓。
建议用途生成按钮、AI 施法动效、主 Logo 备选微调方向。
### 4.4 作品胶囊
![作品胶囊](../../public/branding/taonier-logo-v3-concepts/taonier-v3-work-gem.png)
定位:精品内容和作品沉淀。
这个方向更稳、更精品,青绿色也比褐色更吸睛。但整体像水滴、宝石或通用内容图标,和“捏”这个动作的关系弱。
建议用途:精选作品、作品库、创作者中心,不建议优先做主 Logo。
### 4.5 软体 T 形
![软体 T 形](../../public/branding/taonier-logo-v3-concepts/taonier-v3-soft-t.png)
定位:英文辅助名 / Taonier 的抽象首字母。
这个方向试图做更品牌化的抽象符号,但当前形体还不够自然,也未形成足够强的“陶泥儿”心智。若未来英文名确定为 `Taonier` 或类似形式,可以继续沿这个方向做专业字母标重绘。
建议用途:英文标识探索,不作为当前主 Logo 首选。
## 5. V2 扁平矢量候选
第一批图形偏 3D 和拟物,更适合作为吉祥物、运营图或启动页气氛图,不适合作为长期主 Logo。V2 已把约束收紧为扁平、矢量、少元素、强轮廓和小尺寸可识别。
![陶泥儿 Logo 扁平概念总览](../../public/branding/taonier-logo-flat-concepts/taonier-logo-flat-contact-sheet.png)
### 5.1 扁平开捏
![扁平开捏](../../public/branding/taonier-logo-flat-concepts/taonier-flat-play-clay.png)
定位:最直接的主 Logo 候选。
这个方向用一团柔软陶泥承载播放符号,用户一眼能理解“点开玩 / 马上玩”,同时外形保留“捏出来”的不规则软泥感。
优点:
- 识别速度最快,移动端小尺寸也成立。
- 符合主流 App Logo 语言,亲和、不重、不技术冷。
- 和“把脑洞捏成小游戏”的主张绑定最强。
风险:
- 播放符号是常见母题,后续矢量化时要通过不规则软泥外轮廓、颜色和字标形成独特资产。
建议用途:主 Logo 首选、App icon、平台顶栏、分享卡片角标。
### 5.2 灵感泥星
![灵感泥星](../../public/branding/taonier-logo-flat-concepts/taonier-flat-spark-clay.png)
定位AI 创作与灵感生成。
这个方向比“扁平开捏”更品牌化中心负形星点表达灵感、AI 生成和创意爆发。它没有播放符号那么直白,但更容易和“陶泥儿”的创作平台气质绑定。
优点:
- 图形更简洁,品牌记忆点强。
- 陶泥心智、AI 灵感和精品感比较平衡。
- 适合未来扩成字标、启动页和生成态动效。
风险:
- 对“小游戏/马上玩”的表达弱于播放符号。
建议用途:主 Logo 强备选、创作首页、AI 生成按钮和品牌主视觉。
### 5.3 造梗笑泥
![造梗笑泥](../../public/branding/taonier-logo-flat-concepts/taonier-flat-meme-smile.png)
定位:社交传播和玩梗亲和力。
这个方向的气泡与笑脸非常亲和,适合表达“分享快乐”和“造梗”。但它和聊天、社区类产品的通用图形过近,作为主 Logo 可能会让用户误判产品品类。
建议用途:社区、评论、分享、活动贴纸,不建议做主 Logo。
### 5.4 共创泥环
![共创泥环](../../public/branding/taonier-logo-flat-concepts/taonier-flat-loop-mold.png)
定位AI 与用户共创闭环。
这个方向表达共创与循环,但生成结果带有偏柔和彩虹渐变的视觉倾向,与“陶泥儿”的软泥名称关联不够直观,也不如 01/02 容易记住。
建议用途:创作流程、共创能力、生成进度辅助图形。
### 5.5 精品泥印
![精品泥印](../../public/branding/taonier-logo-flat-concepts/taonier-flat-seal-blocks.png)
定位:精品作品和内容集合。
这个方向像内容平台或作品库入口,能表达图片、用户、游戏等多形态内容。但图形元素较多,主标识别不如 01/02 凝练。
建议用途:精选作品、作品集、创作者中心、内容品质标识。
## 6. V1 立体探索
### 6.1 灵感陶团
![灵感陶团](../../public/branding/taonier-logo-concepts/taonier-clay-spark.png)
定位AI 共创与灵感造物。
这个方向把“陶泥”作为主视觉,内部用发光火花和节点表达 AI 赋能。它最贴“陶泥儿”名字本身,也能说明平台不是普通小游戏集合,而是从灵感生成作品的创作容器。
优点:
- 与“陶泥儿”的名称绑定最强。
- 有 AI、创作、造物的综合含义。
- 适合启动页、品牌介绍、创作首页空状态。
风险:
- 小尺寸下细节偏多,需要后续矢量化时压缩节点和纹理。
- 如果色彩处理不当,会回到手工陶艺联想。
建议用途:品牌主视觉备选、官网/启动页、创作入口图形。
### 6.2 开玩模具
![开玩模具](../../public/branding/taonier-logo-concepts/taonier-play-mold.png)
定位:把脑洞捏成小游戏。
这个方向用软陶捏出播放符号,最直接地连接“创作”和“马上玩”。它比单纯陶泥团更有产品动作,也更适合轻休闲、小游戏、短内容传播。
优点:
- 识别强,小尺寸也清楚。
- 与轻度休闲小游戏的关系最直接。
- 适合作为 App icon 和主 Logo 图形。
风险:
- 播放符号相对常见,需要后续在外轮廓、捏痕和色彩上做独特性。
- 如果三角形过硬,会削弱“陶泥儿”的柔软感。
建议用途:主 Logo 首选、App icon、分享卡片角标、加载态图形。
### 6.3 造梗气泡
![造梗气泡](../../public/branding/taonier-logo-concepts/taonier-meme-bubble.png)
定位:社交传播、玩梗、裂变。
这个方向把陶泥变形成聊天气泡和表情,强调“梗”和“传播”。它最有社交平台感,也适合表情包、活动贴纸和运营视觉。
优点:
- 传播感强,年轻、轻松、容易做 IP 化。
- 能承接社区、评论、分享和玩梗场景。
- 比较容易延展成贴纸和表情包。
风险:
- 偏软萌,可能削弱“精品 AI 创作平台”的质感。
- 作为主 Logo 容易显得像聊天或表情产品。
建议用途社区模块、活动运营、IP 辅助形象,不建议作为唯一主 Logo。
### 6.4 共创回路
![共创回路](../../public/branding/taonier-logo-concepts/taonier-creation-loop.png)
定位AI 与用户共同迭代生成。
这个方向用软陶带形成循环和造物轨迹,表达“灵感 -> AI 塑形 -> 用户修改 -> 作品传播”的闭环。它比其他方向更抽象,也更有平台级和工具级气质。
优点:
- 高级、简洁,避免儿童化。
- 适合表达 AI 共创、迭代和作品循环。
- 可用于创作者工作台或生成进度标识。
风险:
- 与“陶泥儿”名称的直观关联较弱。
- 缺少小游戏和玩梗的即时识别。
建议用途创作流程标识、AI 共创能力图标、品牌辅助图形。
### 6.5 精品泥印
![精品泥印](../../public/branding/taonier-logo-concepts/taonier-premium-seal.png)
定位:精品内容、作品认证、创作者成果。
这个方向像一个被压印的软陶徽章,中间有方块和火花,比较适合表达“作品被打磨成型”。它的内容平台感强于游戏入口感。
优点:
- 精品感和作品库气质较强。
- 适合作品认证、精选、创作者徽章。
- 与“陶泥压印”隐喻相对自然。
风险:
- 细节较多,主 Logo 小尺寸可读性不如“开玩模具”。
- 徽章感偏静态,轻休闲的即时性稍弱。
建议用途:精选作品标识、创作者荣誉、内容品质标签。
## 7. 推荐结论
优先级建议:
```text
主 Logo 首选V3 01 灵感捏痕
一捏成型首选V3-03 延展 01 捏合星核
完整主标备选V3-03 延展 02 成型印记
英文标识探索V3 05 软体 T 形
精品内容辅助V3 04 作品胶囊
新手 / 寓教于乐辅助V3 02 脑洞种子
```
若要兼顾主流、亲和、醒目和“陶泥儿”的动作隐喻,优先继续打磨 V3 “灵感捏痕”。
若想把 Logo 做得更抽象、更像 AI 生成瞬间,可以继续打磨 V3-03 延展中的“捏合星核”或“成型印记”。
V1 的 3D 图标不建议直接作为主 Logo只适合做运营图、吉祥物探索或风格参考V2 的播放、气泡、碎元素方向本轮已降级为历史探索。
## 8. 后续落地建议
1. 先围绕 V3 “灵感捏痕”做 3 到 5 个专业矢量微调版:减少指纹线条、强化软形轮廓、测试深色 / 浅色底。
2. 同步对 V3-03 “捏合星核”做一版更独特的轮廓重绘,弱化括号感,保留中央成型星核。
3. 字标不要直接使用生图结果,应单独设计“陶泥儿”中文字标,并准备英文辅助名。
4. 正式应用前做商标近似检索,重点覆盖第 9、35、38、41、42 类。
5. 若确认替换“百梦”再更新现有命名规范文档、前端品牌组件、HTML metadata、后台和后端默认文案。

View File

@@ -122,6 +122,7 @@
## 9. 2026-05-08 创作首页通知入口下线 ## 9. 2026-05-08 创作首页通知入口下线
- `CreativeAgentHome` 顶栏右上角不再展示“通知与账户”按钮,避免创作首页把通知入口放在首屏高频区域。 - `CreativeAgentHome` 顶栏右上角不再展示“通知与账户”按钮,避免创作首页把通知入口放在首屏高频区域。
- 2026-05-12 平台入口页同步移除移动端和桌面端右上角通知铃铛;移动端顶栏只保留品牌,未登录时保留登录按钮,桌面端只保留账号入口。
- 账号入口仍保留在侧边栏底部,创作首页顶栏维持左侧菜单、居中品牌的轻量结构。 - 账号入口仍保留在侧边栏底部,创作首页顶栏维持左侧菜单、居中品牌的轻量结构。
- 当前账号相关入口统一保留在平台首页受保护动作、个人页、存档页与账号弹窗,不再占用全局悬浮层。 - 当前账号相关入口统一保留在平台首页受保护动作、个人页、存档页与账号弹窗,不再占用全局悬浮层。
@@ -220,4 +221,12 @@
--- ---
## 19. 2026-05-12 登录协议与个人页法律入口
- 登录弹窗的法律协议确认应挂在短信 / 密码登录提交按钮上方,法律链接只打开独立 `LegalDocumentModal`,不能顺手勾选同意。
- 法律弹窗通过 portal 挂到 `body` 时必须显式带 `platform-theme--*` 和高于登录遮罩的层级,否则容易丢主题变量或被登录弹窗遮住。
- “我的”页常用功能区固定为 3 列,法律信息区放在设置入口下方;备案号作为外链进入工信部备案站,入口保持轻量,不在页面内展开长文。
---
_文档目的交接给下一个 Agent 时,优先读本文件 + `UI_CODING_STANDARD.md`,再改 `uiAssets.ts` / `App.tsx` / `index.css`。_ _文档目的交接给下一个 Agent 时,优先读本文件 + `UI_CODING_STANDARD.md`,再改 `uiAssets.ts` / `App.tsx` / `index.css`。_

View File

@@ -29,7 +29,7 @@
结论: 结论:
- 独立编辑器入口如果没有继续接入主流程,应及时物理删除,不要长期保留兼容壳 - 独立编辑器入口如果没有继续接入主流程,应及时物理删除,不要长期保留兼容壳
- 页签命名要贴近百梦主语言,而不是内部实现命名 - 页签命名要贴近陶泥儿主语言,而不是内部实现命名
### 2.2 NPC 视觉模块并入 NPC 编辑 ### 2.2 NPC 视觉模块并入 NPC 编辑
@@ -144,7 +144,7 @@
经验: 经验:
- 百梦主并不关心 “function” 这个技术词,更关心“这个选项会发生什么” - 陶泥儿主并不关心 “function” 这个技术词,更关心“这个选项会发生什么”
- 同类编辑器如果只给字段表单而没有模板起稿能力,复用效率会很低 - 同类编辑器如果只给字段表单而没有模板起稿能力,复用效率会很低
### 2.8 选项行为预览升级到实机回放 ### 2.8 选项行为预览升级到实机回放
@@ -217,7 +217,7 @@
- 预览面板要么都显示“实时状态” - 预览面板要么都显示“实时状态”
- 要么都显示“同一个阶段的快照” - 要么都显示“同一个阶段的快照”
- 混用实时值和预测值会让百梦主误判 - 混用实时值和预测值会让陶泥儿主误判
## 4. 这类项目里沉淀下来的方法论 ## 4. 这类项目里沉淀下来的方法论
@@ -245,7 +245,7 @@
- 不是所有字段都应该在所有行为类型下开放 - 不是所有字段都应该在所有行为类型下开放
- 如果某类行为最终不会直接读取某个字段,就应该禁用或弱化它 - 如果某类行为最终不会直接读取某个字段,就应该禁用或弱化它
- 否则百梦主会错误地以为改动无效是 bug - 否则陶泥儿主会错误地以为改动无效是 bug
### 4.4 模板比空白表单更重要 ### 4.4 模板比空白表单更重要

View File

@@ -25,7 +25,7 @@
3. 历史已发布作品必须能自动补齐 gallery 投影。 3. 历史已发布作品必须能自动补齐 gallery 投影。
- 公开列表读取 `list_custom_world_gallery_entries` 前,会扫描 `custom_world_profile` 中已发布且未删除的 profile。 - 公开列表读取 `list_custom_world_gallery_entries` 前,会扫描 `custom_world_profile` 中已发布且未删除的 profile。
- 若已发布 profile 缺少 `custom_world_gallery_entry`,或缺少公开作品码 / 作者百梦号,会先补齐公开字段并同步 gallery 投影。 - 若已发布 profile 缺少 `custom_world_gallery_entry`,或缺少公开作品码 / 作者陶泥号,会先补齐公开字段并同步 gallery 投影。
- 这样旧版本发布成功但未落入广场读模型的作品,在下一次首页 / 分类页读取公开列表时会自动出现。 - 这样旧版本发布成功但未落入广场读模型的作品,在下一次首页 / 分类页读取公开列表时会自动出现。
## 经验 ## 经验

View File

@@ -394,7 +394,7 @@ MVP 阶段不需要单独设置密码。
落地规则: 落地规则:
- 入参只允许 `phone``password`,不支持邮箱、用户名或百梦号。 - 入参只允许 `phone``password`,不支持邮箱、用户名或陶泥号。
- 手机号不存在时,不创建账号,返回统一的登录失败。 - 手机号不存在时,不创建账号,返回统一的登录失败。
- 手机号存在但账号未设置过密码时,不允许密码登录。 - 手机号存在但账号未设置过密码时,不允许密码登录。
- 首次设置密码只能在已登录账号中心内完成;用户必须先通过手机号验证码或已绑定手机号的微信账号进入已登录态。 - 首次设置密码只能在已登录账号中心内完成;用户必须先通过手机号验证码或已绑定手机号的微信账号进入已登录态。
@@ -734,7 +734,7 @@ MVP 阶段建议至少提供一个轻量账号中心,包含:
约束: 约束:
- 不支持邮箱、用户名或百梦号。 - 不支持邮箱、用户名或陶泥号。
- 不承担注册能力。 - 不承担注册能力。
- 只有已存在、已验证手机号、且 `passwordLoginEnabled=true` 的账号可以登录。 - 只有已存在、已验证手机号、且 `passwordLoginEnabled=true` 的账号可以登录。

View File

@@ -55,7 +55,7 @@
- 调用 `POST /admin/api/profile/redeem-codes` 创建/更新兑换码。 - 调用 `POST /admin/api/profile/redeem-codes` 创建/更新兑换码。
- 调用 `POST /admin/api/profile/redeem-codes/disable` 停用兑换码。 - 调用 `POST /admin/api/profile/redeem-codes/disable` 停用兑换码。
- 支持 `public``unique``private` 三种模式。 - 支持 `public``unique``private` 三种模式。
- 私有码支持输入内部 `userId` 和公开百梦号,提交给后端统一解析。 - 私有码支持输入内部 `userId` 和公开陶泥号,提交给后端统一解析。
7. 邀请码管理页: 7. 邀请码管理页:
- 调用 `POST /admin/api/profile/invite-codes` 创建/更新注册邀请码。 - 调用 `POST /admin/api/profile/invite-codes` 创建/更新注册邀请码。
- 支持输入 JSON 对象 metadata提交前做基础 JSON 对象校验,最终校验以服务端为准。 - 支持输入 JSON 对象 metadata提交前做基础 JSON 对象校验,最终校验以服务端为准。
@@ -114,7 +114,7 @@ API 调试页是受控接口调试台,不是通用代理工具:
4. maxUses必须为正整数最终校验以服务端为准。 4. maxUses必须为正整数最终校验以服务端为准。
5. enabled创建/更新时可切换。 5. enabled创建/更新时可切换。
6. allowedUserIds私有码允许的内部用户 ID 列表。 6. allowedUserIds私有码允许的内部用户 ID 列表。
7. allowedPublicUserCodes私有码允许的公开百梦号列表。 7. allowedPublicUserCodes私有码允许的公开陶泥号列表。
提交成功后展示后端返回的兑换码记录;失败时展示后端错误消息。 提交成功后展示后端返回的兑换码记录;失败时展示后端错误消息。

View File

@@ -12,7 +12,7 @@
## 1. 一句话定义 ## 1. 一句话定义
`2048` 是一个主题化数字合成玩法模板:百梦主通过 Agent 设定棋盘主题、合成链、视觉皮肤、目标格和难度参数,系统生成可试玩、可发布的 2048 作品;玩家通过滑动方向移动棋盘格,相同等级方块合并升级,直到达成目标格或棋盘无可行动作。 `2048` 是一个主题化数字合成玩法模板:陶泥儿主通过 Agent 设定棋盘主题、合成链、视觉皮肤、目标格和难度参数,系统生成可试玩、可发布的 2048 作品;玩家通过滑动方向移动棋盘格,相同等级方块合并升级,直到达成目标格或棋盘无可行动作。
--- ---
@@ -108,7 +108,7 @@ Agent 型创作至少收集下面 5 个锚点:
Agent 行为要求: Agent 行为要求:
1. 优先接住百梦主的一句话灵感,不把创作变成问卷。 1. 优先接住陶泥儿主的一句话灵感,不把创作变成问卷。
2. 每轮最多追问 1 个最影响成品质量的问题。 2. 每轮最多追问 1 个最影响成品质量的问题。
3. 当主题和合成链已经足够明确时,优先生成草稿。 3. 当主题和合成链已经足够明确时,优先生成草稿。
4. 合成链必须围绕同一主题递进,不允许出现互不相关的方块名。 4. 合成链必须围绕同一主题递进,不允许出现互不相关的方块名。
@@ -860,4 +860,4 @@ npm run check:encoding
## 20. 一句话结论 ## 20. 一句话结论
`2048` 在 Genarrative 中应被做成一个可创作、可换皮、可发布、可排行的主题合成棋盘模板:创作端让百梦主定义合成链和视觉承诺,运行端保持经典 2048 的滑动合并手感,服务端负责正式棋盘裁决、作品状态和成绩真相。 `2048` 在 Genarrative 中应被做成一个可创作、可换皮、可发布、可排行的主题合成棋盘模板:创作端让陶泥儿主定义合成链和视觉承诺,运行端保持经典 2048 的滑动合并手感,服务端负责正式棋盘裁决、作品状态和成绩真相。

View File

@@ -31,7 +31,7 @@
大鱼吃小鱼玩法是一个 `Agent-First` 的轻量实时成长玩法创作链: 大鱼吃小鱼玩法是一个 `Agent-First` 的轻量实时成长玩法创作链:
**百梦主先与 Agent 共创“进化母题、等级阶梯、生态风格与场地气质”,系统再自动编译出一个竖屏全屏、摇杆移动、吞噬收编、三合一进化、持续刷怪、升到最高级即通关的可运行玩法作品。** **陶泥儿主先与 Agent 共创“进化母题、等级阶梯、生态风格与场地气质”,系统再自动编译出一个竖屏全屏、摇杆移动、吞噬收编、三合一进化、持续刷怪、升到最高级即通关的可运行玩法作品。**
--- ---
@@ -115,26 +115,26 @@
`Agent-First 大鱼吃小鱼玩法创作工具` `Agent-First 大鱼吃小鱼玩法创作工具`
玩法运行态对外展示名可由百梦主自定义,不强绑平台内部域名。 玩法运行态对外展示名可由陶泥儿主自定义,不强绑平台内部域名。
## 5.2 目标用户 ## 5.2 目标用户
目标用户主要是 3 类: 目标用户主要是 3 类:
1.百梦 1.陶泥儿
- 想快速做一个可玩的成长吞噬小游戏,但不懂完整关卡编辑器 - 想快速做一个可玩的成长吞噬小游戏,但不懂完整关卡编辑器
2. 视觉驱动型百梦 2. 视觉驱动型陶泥儿
- 更关心“每级长什么样、动作怎么样、背景氛围如何” - 更关心“每级长什么样、动作怎么样、背景氛围如何”
3. 玩法原型百梦 3. 玩法原型陶泥儿
- 想快速验证一套吞噬成长节奏、等级曲线和场地压迫感 - 想快速验证一套吞噬成长节奏、等级曲线和场地压迫感
## 5.3 成功标准 ## 5.3 成功标准
本期上线后,至少要满足下面这些结果: 本期上线后,至少要满足下面这些结果:
1. 百梦主可在 `5~12` 分钟内通过 Agent 聊天形成一版可用锚点草稿。 1. 陶泥儿主可在 `5~12` 分钟内通过 Agent 聊天形成一版可用锚点草稿。
2. 系统默认能编译出 `8` 级实体阶梯的初版玩法草稿。 2. 系统默认能编译出 `8` 级实体阶梯的初版玩法草稿。
3. 每一级实体都能在结果页单独生成和重生成主图。 3. 每一级实体都能在结果页单独生成和重生成主图。
4. 每一级实体都能在结果页单独生成和重生成动作。 4. 每一级实体都能在结果页单独生成和重生成动作。
@@ -179,9 +179,9 @@
Agent 在这一玩法里不负责实时玩法裁决,它只负责 3 件事: Agent 在这一玩法里不负责实时玩法裁决,它只负责 3 件事:
1.百梦主明确高杠杆锚点 1.陶泥儿主明确高杠杆锚点
2.百梦主把模糊灵感总结成可编译结构 2.陶泥儿主把模糊灵感总结成可编译结构
3.百梦主收束出第一版等级阶梯与视觉方向 3.陶泥儿主收束出第一版等级阶梯与视觉方向
## 7.2 前台交互原则 ## 7.2 前台交互原则
@@ -222,7 +222,7 @@ Agent 在这一玩法里不负责实时玩法裁决,它只负责 3 件事:
3. `成长阶梯` 3. `成长阶梯`
- 这一玩法一共大致有几级,以及每一级如何逐步升级、变大、变强、变异 - 这一玩法一共大致有几级,以及每一级如何逐步升级、变大、变强、变异
- 最高级终局形态也并入这一锚点统一确定 - 最高级终局形态也并入这一锚点统一确定
-百梦主没有明确总层数,本期默认按 `8` 级编译,可配置范围固定为 `6~12` -陶泥儿主没有明确总层数,本期默认按 `8` 级编译,可配置范围固定为 `6~12`
4. `风险节奏` 4. `风险节奏`
- 玩家周围应该更偏压迫、平衡还是偏爽快 - 玩家周围应该更偏压迫、平衡还是偏爽快
@@ -235,7 +235,7 @@ Agent 在这一玩法里不负责实时玩法裁决,它只负责 3 件事:
2. `等级总层数` 并入 `成长阶梯` 2. `等级总层数` 并入 `成长阶梯`
3. `升级轮廓` 并入 `成长阶梯` 3. `升级轮廓` 并入 `成长阶梯`
4. `终局形态` 并入 `成长阶梯` 4. `终局形态` 并入 `成长阶梯`
5. `开局成长方式` 改为系统固定规则,不再作为百梦主锚点 5. `开局成长方式` 改为系统固定规则,不再作为陶泥儿主锚点
后续 Agent 追问时,不再把这些内容拆成独立必答题。 后续 Agent 追问时,不再把这些内容拆成独立必答题。
@@ -302,7 +302,7 @@ Agent 在这一玩法里不负责实时玩法裁决,它只负责 3 件事:
## 9.1 默认草稿规模 ## 9.1 默认草稿规模
百梦主没有特别指定时,第一版玩法草稿必须默认编译为: 陶泥儿主没有特别指定时,第一版玩法草稿必须默认编译为:
1. `8` 级实体阶梯 1. `8` 级实体阶梯
2. `1` 张活动区域背景图 2. `1` 张活动区域背景图

View File

@@ -680,7 +680,7 @@ assistant 回复应包含:
1. 对 seedText / 用户消息的简要复述 1. 对 seedText / 用户消息的简要复述
2. 当前仍缺哪些世界锚点 2. 当前仍缺哪些世界锚点
3. 建议百梦主下一步回答什么 3. 建议陶泥儿主下一步回答什么
#### 用户后续消息 #### 用户后续消息

View File

@@ -24,7 +24,7 @@
那么第二阶段的目标就是: 那么第二阶段的目标就是:
**让 Agent 会话真正开始理解百梦主输入,并把自然语言聊天沉淀成结构化创作锚点。** **让 Agent 会话真正开始理解陶泥儿主输入,并把自然语言聊天沉淀成结构化创作锚点。**
一句话定义: 一句话定义:

View File

@@ -26,7 +26,7 @@
那么第四阶段的目标就是: 那么第四阶段的目标就是:
**让百梦主直接修改这版草稿设定,并且继续用 AI 为这版草稿扩出新的角色和场景。** **让陶泥儿主直接修改这版草稿设定,并且继续用 AI 为这版草稿扩出新的角色和场景。**
一句话定义: 一句话定义:
@@ -100,7 +100,7 @@
一句话目标: 一句话目标:
**让第四阶段结束时,百梦主第一次能像在真正做作品一样修改草稿、继续长出新对象。** **让第四阶段结束时,陶泥儿主第一次能像在真正做作品一样修改草稿、继续长出新对象。**
--- ---

View File

@@ -200,7 +200,7 @@
1. 主线关键角色 1. 主线关键角色
2. 可扮演角色 2. 可扮演角色
3. 百梦主重点想看的角色 3. 陶泥儿主重点想看的角色
## 7.2 入口位置 ## 7.2 入口位置

View File

@@ -42,21 +42,21 @@
## 1.2 一句话定义 ## 1.2 一句话定义
百梦主通过与一个懂 RPG 剧情策划方法的 Agent 对话,逐步完成世界锚点收集、关键对象塑造、剧情骨架搭建和长尾内容展开;同时由 Express 后端持续维护结构化世界状态、锁定边界、局部重生成和质量检查。 陶泥儿主通过与一个懂 RPG 剧情策划方法的 Agent 对话,逐步完成世界锚点收集、关键对象塑造、剧情骨架搭建和长尾内容展开;同时由 Express 后端持续维护结构化世界状态、锁定边界、局部重生成和质量检查。
## 1.3 目标用户 ## 1.3 目标用户
目标用户分三类: 目标用户分三类:
1.百梦 1.陶泥儿
- 有世界灵感,但不擅长结构化填表 - 有世界灵感,但不擅长结构化填表
2. 中度百梦 2. 中度陶泥儿
- 愿意精修角色、地点、主线第一幕,但不想维护大量底层字段 - 愿意精修角色、地点、主线第一幕,但不想维护大量底层字段
3. 重度百梦 3. 重度陶泥儿
- 需要局部重生成、锁定、版本化和导出世界圣经 - 需要局部重生成、锁定、版本化和导出世界圣经
## 1.4 产品成功标准 ## 1.4 产品成功标准
@@ -76,7 +76,7 @@
1. 不把整套系统做成纯聊天黑箱。 1. 不把整套系统做成纯聊天黑箱。
2. 不让前端继续承担锁定合并、重生成裁决、结构编译等核心逻辑。 2. 不让前端继续承担锁定合并、重生成裁决、结构编译等核心逻辑。
3. 不要求百梦主直接编辑 `ThemePack / WorldStoryGraph / VisibilitySlice / ThreadContract` 等运行时结构。 3. 不要求陶泥儿主直接编辑 `ThemePack / WorldStoryGraph / VisibilitySlice / ThreadContract` 等运行时结构。
4. 不把长项目世界管理完全交给一条无限增长的聊天记录。 4. 不把长项目世界管理完全交给一条无限增长的聊天记录。
5. 不再保留“生成完直接回世界列表并自动保存”的旧流程。 5. 不再保留“生成完直接回世界列表并自动保存”的旧流程。
6. 不允许角色主图、角色动作、场景背景图继续停留在临时候选状态后直接发布世界。 6. 不允许角色主图、角色动作、场景背景图继续停留在临时候选状态后直接发布世界。
@@ -151,7 +151,7 @@
1. `src/services/customWorldCreatorIntent.ts` 1. `src/services/customWorldCreatorIntent.ts`
- 已有百梦主意图、锚点包、锁定状态的基础结构 - 已有陶泥儿主意图、锚点包、锁定状态的基础结构
2. `src/types/customWorld.ts` 2. `src/types/customWorld.ts`
@@ -228,7 +228,7 @@
后台必须持续维护: 后台必须持续维护:
1. 百梦主意图 1. 陶泥儿主意图
2. 锁定状态 2. 锁定状态
3. 世界底稿快照 3. 世界底稿快照
4. 可编辑草稿对象列表 4. 可编辑草稿对象列表
@@ -271,11 +271,11 @@
-> 打开 Agent 创作入口 -> 打开 Agent 创作入口
-> Agent 收集最小锚点 -> Agent 收集最小锚点
-> Agent 输出首轮世界底稿 -> Agent 输出首轮世界底稿
-> 百梦主锁定/修改关键内容 -> 陶泥儿主锁定/修改关键内容
-> Agent 局部生成关键角色/地点/主线第一幕 -> Agent 局部生成关键角色/地点/主线第一幕
-> 进入角色与场景资产工坊,生成主形象 / 动作 / 背景图 -> 进入角色与场景资产工坊,生成主形象 / 动作 / 背景图
-> Agent 扩展长尾内容 -> Agent 扩展长尾内容
-> 百梦主发布世界 -> 陶泥儿主发布世界
-> 保存到世界库并进入世界 -> 保存到世界库并进入世界
``` ```
@@ -2077,4 +2077,4 @@ Agent 会话每次 operation 完成后自动保存 session snapshot。
这次新创作工具的正确方向,不是把现有工作台换成一个更大的聊天框,而是: 这次新创作工具的正确方向,不是把现有工作台换成一个更大的聊天框,而是:
**让 Agent 成为百梦主的主交互入口,让 Express 后端成为真正的世界状态管理者,让锁定、局部重生成、摘要、质量护栏和发布链把整个创作过程牢牢收住。** **让 Agent 成为陶泥儿主的主交互入口,让 Express 后端成为真正的世界状态管理者,让锁定、局部重生成、摘要、质量护栏和发布链把整个创作过程牢牢收住。**

View File

@@ -37,15 +37,15 @@
## 1.3 目标用户 ## 1.3 目标用户
目标用户仍然是当前自定义世界创作工具的三类百梦主,但本流程更偏向解决其中两类人的起步问题: 目标用户仍然是当前自定义世界创作工具的三类陶泥儿主,但本流程更偏向解决其中两类人的起步问题:
1.百梦 1.陶泥儿
- 有模糊灵感,但不知道先想什么 - 有模糊灵感,但不知道先想什么
2. 中度百梦 2. 中度陶泥儿
- 有一些设定点子,但缺少把设定收束成可运行剧情骨架的方法 - 有一些设定点子,但缺少把设定收束成可运行剧情骨架的方法
重度百梦主也可使用本流程,但他们更关心的是: 重度陶泥儿主也可使用本流程,但他们更关心的是:
- Agent 是否会少问废话 - Agent 是否会少问废话
- 摘要是否准确 - 摘要是否准确
@@ -1190,7 +1190,7 @@ Agent 不应回复成八问表:
## 13.2 后续可编辑范围 ## 13.2 后续可编辑范围
进入世界底稿阶段后,百梦主默认优先精修: 进入世界底稿阶段后,陶泥儿主默认优先精修:
1. 关键角色 1. 关键角色
2. 核心冲突与线程 2. 核心冲突与线程

View File

@@ -1,4 +1,4 @@
# AI 原生自定义世界生成流程优化 PRD # AI 原生自定义世界生成流程优化 PRD
更新时间:`2026-04-06` 更新时间:`2026-04-06`
@@ -8,11 +8,11 @@
目标不是推翻当前已经存在的多阶段生成链,而是解决下面这个核心错位: 目标不是推翻当前已经存在的多阶段生成链,而是解决下面这个核心错位:
**当前仓库已经开始把世界生成拆成 `framework -> themePack -> storyGraph -> role outline -> dossier -> narrativeProfile` 的分阶段 AI 编译流程,但百梦主入口仍然是“一段大文本”,结果页又把大量低杠杆字段重新扔回给百梦主人工兜底。** **当前仓库已经开始把世界生成拆成 `framework -> themePack -> storyGraph -> role outline -> dossier -> narrativeProfile` 的分阶段 AI 编译流程,但陶泥儿主入口仍然是“一段大文本”,结果页又把大量低杠杆字段重新扔回给陶泥儿主人工兜底。**
一句话定义本次优化: 一句话定义本次优化:
**让百梦主先定义世界灵魂锚点,再让 AI / 系统围绕锚点分层生成、分层展开、分层可控地完成长尾内容。** **让陶泥儿主先定义世界灵魂锚点,再让 AI / 系统围绕锚点分层生成、分层展开、分层可控地完成长尾内容。**
## 1. 当前流程现状 ## 1. 当前流程现状
@@ -64,7 +64,7 @@
## 1.3 当前流程的核心问题 ## 1.3 当前流程的核心问题
## 1.3.1 百梦主入口过于粗糙 ## 1.3.1 陶泥儿主入口过于粗糙
当前创建入口只有一块大文本输入框。 当前创建入口只有一块大文本输入框。
@@ -72,23 +72,23 @@
1. 不会写长描述的用户很难开局。 1. 不会写长描述的用户很难开局。
2. 愿意精细创作的用户没有结构化落点。 2. 愿意精细创作的用户没有结构化落点。
3. 系统无法明确分辨“哪些是百梦主真正想锁定的锚点,哪些只是随口补充的描述”。 3. 系统无法明确分辨“哪些是陶泥儿主真正想锁定的锚点,哪些只是随口补充的描述”。
结果就是: 结果就是:
**输入端自由但信息信号不稳定AI 虽然能生成很多内容,却不一定生成的是百梦主真正关心的内容。** **输入端自由但信息信号不稳定AI 虽然能生成很多内容,却不一定生成的是陶泥儿主真正关心的内容。**
## 1.3.2 百梦主与 AI 的职责发生倒置 ## 1.3.2 陶泥儿主与 AI 的职责发生倒置
当前流程实际上是: 当前流程实际上是:
- 百梦主先写一段泛化设定 - 陶泥儿主先写一段泛化设定
- AI 再把整个世界铺满 - AI 再把整个世界铺满
- 百梦主最后回到结果页,人工修改大量角色、章节、技能、初始物品、场景连接等细节 - 陶泥儿主最后回到结果页,人工修改大量角色、章节、技能、初始物品、场景连接等细节
这与“低创作门槛、高创作自由度”的目标相反。 这与“低创作门槛、高创作自由度”的目标相反。
因为真正应该由百梦主控制的,是: 因为真正应该由陶泥儿主控制的,是:
- 世界核心命题 - 世界核心命题
- 主题与气质 - 主题与气质
@@ -98,7 +98,7 @@
- 关键地点 - 关键地点
- 标志性物件 / 怪物 / 禁忌 - 标志性物件 / 怪物 / 禁忌
而不是让百梦主在结果页里逐个补: 而不是让陶泥儿主在结果页里逐个补:
- `backstoryReveal.chapters` - `backstoryReveal.chapters`
- `skills` - `skills`
@@ -117,13 +117,13 @@
问题不在数量本身,而在于系统并没有明确区分: 问题不在数量本身,而在于系统并没有明确区分:
1. 哪些是百梦主应重点塑造的关键对象 1. 哪些是陶泥儿主应重点塑造的关键对象
2. 哪些只是 AI 应自动展开的长尾铺量 2. 哪些只是 AI 应自动展开的长尾铺量
这会导致两个问题: 这会导致两个问题:
1. AI 在早期就花大量成本生成长尾内容,等待时间长。 1. AI 在早期就花大量成本生成长尾内容,等待时间长。
2. 百梦主在结果页里面对的是一整套“全部都生成了”的世界,而不是“先抓关键锚点,再决定是否继续铺开”。 2. 陶泥儿主在结果页里面对的是一整套“全部都生成了”的世界,而不是“先抓关键锚点,再决定是否继续铺开”。
## 1.3.4 当前结果页暴露了过多低杠杆字段 ## 1.3.4 当前结果页暴露了过多低杠杆字段
@@ -134,7 +134,7 @@
- 场景 NPC 分配 - 场景 NPC 分配
- 场景连接网络 - 场景连接网络
这对“专业百梦主”当然有帮助,但对目标用户来说,容易把工具变成: 这对“专业陶泥儿主”当然有帮助,但对目标用户来说,容易把工具变成:
**看起来自由度很高,实际上需要承担很多系统编辑工作。** **看起来自由度很高,实际上需要承担很多系统编辑工作。**
@@ -144,11 +144,11 @@
这意味着: 这意味着:
1. 百梦主一旦修改过内容,就会担心被覆盖。 1. 陶泥儿主一旦修改过内容,就会担心被覆盖。
2. 没有“锁定关键内容,只重生成长尾部分”的机制。 2. 没有“锁定关键内容,只重生成长尾部分”的机制。
3. AI 无法真正成为创作搭档,只像一次性大批量生成器。 3. AI 无法真正成为创作搭档,只像一次性大批量生成器。
## 1.3.6 当前生成阶段是“模型视角”,不是“百梦主视角” ## 1.3.6 当前生成阶段是“模型视角”,不是“陶泥儿主视角”
当前生成页展示的是系统批次和阶段进度,这很好,但它主要回答的是: 当前生成页展示的是系统批次和阶段进度,这很好,但它主要回答的是:
@@ -156,7 +156,7 @@
没有回答的是: 没有回答的是:
- 百梦主最关心的关键角色是否已经成型 - 陶泥儿主最关心的关键角色是否已经成型
- 世界冲突是否已经稳定 - 世界冲突是否已经稳定
- 当前这轮已经锁定了哪些核心创意 - 当前这轮已经锁定了哪些核心创意
- 接下来生成的是关键锚点,还是长尾内容 - 接下来生成的是关键锚点,还是长尾内容
@@ -170,19 +170,19 @@
这次优化要同时满足 6 个目标: 这次优化要同时满足 6 个目标:
1. 降低输入门槛 1. 降低输入门槛
- 不要求百梦主一上来写长文,不要求理解系统字段。 - 不要求陶泥儿主一上来写长文,不要求理解系统字段。
2. 提高高杠杆创作自由度 2. 提高高杠杆创作自由度
-百梦主直接控制世界灵魂锚点,而不是低价值细节。 -陶泥儿主直接控制世界灵魂锚点,而不是低价值细节。
3. 明确百梦主与 AI 的职责边界 3. 明确陶泥儿主与 AI 的职责边界
- 百梦主负责“决定什么值得创作”AI 负责“把它展开并跑起来”。 - 陶泥儿主负责“决定什么值得创作”AI 负责“把它展开并跑起来”。
4. 保留现有分阶段生成骨架 4. 保留现有分阶段生成骨架
- 不推翻 `framework -> themePack -> storyGraph -> role/landmark` 的已有结构。 - 不推翻 `framework -> themePack -> storyGraph -> role/landmark` 的已有结构。
5. 引入锁定与局部重生成 5. 引入锁定与局部重生成
-百梦主能保住自己在乎的内容,只重做其余部分。 -陶泥儿主能保住自己在乎的内容,只重做其余部分。
6. 把结果页从“数据总表”升级成“创作工作台” 6. 把结果页从“数据总表”升级成“创作工作台”
- 让编辑界面按创作价值组织,而不是按底层对象堆字段。 - 让编辑界面按创作价值组织,而不是按底层对象堆字段。
@@ -192,11 +192,11 @@
优化后的自定义世界流程应该改为: 优化后的自定义世界流程应该改为:
```text ```text
百梦主输入世界锚点 陶泥儿主输入世界锚点
-> AI 编译百梦主意图摘要 -> AI 编译陶泥儿主意图摘要
-> 百梦主确认 / 锁定关键锚点 -> 陶泥儿主确认 / 锁定关键锚点
-> AI 先生成关键角色与关键地点 -> AI 先生成关键角色与关键地点
-> 百梦主可局部修改 / 局部重生成 -> 陶泥儿主可局部修改 / 局部重生成
-> AI 再展开长尾 NPC、长尾场景与运行时编译结构 -> AI 再展开长尾 NPC、长尾场景与运行时编译结构
-> 结果页以“锚点 / 关键对象 / 扩展内容 / 运行时摘要”方式组织 -> 结果页以“锚点 / 关键对象 / 扩展内容 / 运行时摘要”方式组织
-> 保存并进入世界 -> 保存并进入世界
@@ -204,7 +204,7 @@
一句话: 一句话:
**先做创作决策,再做内容展开;先做关键对象,再做长尾铺量;先让百梦主锁定灵魂,再让 AI 扩散世界。** **先做创作决策,再做内容展开;先做关键对象,再做长尾铺量;先让陶泥儿主锁定灵魂,再让 AI 扩散世界。**
## 4. 输入层优化方案 ## 4. 输入层优化方案
@@ -251,7 +251,7 @@
2. 卡片模式 2. 卡片模式
- 用户直接按结构化方式输入世界锚点 - 用户直接按结构化方式输入世界锚点
两种模式最终都编译成统一的百梦主意图对象。 两种模式最终都编译成统一的陶泥儿主意图对象。
## 4.3 必填与选填要分开 ## 4.3 必填与选填要分开
@@ -272,7 +272,7 @@
- 标志性要素 - 标志性要素
- 禁止事项 - 禁止事项
这样既能保证世界最小成型,又不会把百梦主门槛抬高。 这样既能保证世界最小成型,又不会把陶泥儿主门槛抬高。
## 4.3.1 抽象统一“聊天补充设定”能力 ## 4.3.1 抽象统一“聊天补充设定”能力
@@ -307,11 +307,11 @@ RPG 创作工作台、拼图创作工作台、大鱼吃小鱼创作工作台都
1. AI 不得在重生成时覆盖该内容 1. AI 不得在重生成时覆盖该内容
2. 长尾内容只能围绕它展开 2. 长尾内容只能围绕它展开
3. 结果页里应明确显示其为“百梦主锚点” 3. 结果页里应明确显示其为“陶泥儿主锚点”
## 5. 生成链路优化方案 ## 5. 生成链路优化方案
## 5.1 新增“百梦主意图编译层” ## 5.1 新增“陶泥儿主意图编译层”
在真正开始世界生成前,先新增一个轻量阶段: 在真正开始世界生成前,先新增一个轻量阶段:
@@ -324,19 +324,19 @@ RPG 创作工作台、拼图创作工作台、大鱼吃小鱼创作工作台都
输出: 输出:
- 百梦主意图摘要 - 陶泥儿主意图摘要
- 世界锚点摘要 - 世界锚点摘要
- 系统识别出的关键角色 / 冲突 / 地点 / 禁忌 - 系统识别出的关键角色 / 冲突 / 地点 / 禁忌
这一步的作用不是生成世界,而是先回答: 这一步的作用不是生成世界,而是先回答:
1. 系统理解到的世界核心是什么 1. 系统理解到的世界核心是什么
2. 哪些内容将被视为百梦主强锚点 2. 哪些内容将被视为陶泥儿主强锚点
3. 哪些内容将交给 AI 扩展 3. 哪些内容将交给 AI 扩展
## 5.2 把当前生成链改成“关键先行、长尾后补” ## 5.2 把当前生成链改成“关键先行、长尾后补”
当前 `generateCustomWorldProfile(...)` 的分阶段结构可以保留,但生成顺序需要更百梦主化。 当前 `generateCustomWorldProfile(...)` 的分阶段结构可以保留,但生成顺序需要更陶泥儿主化。
建议改成 5 层: 建议改成 5 层:
@@ -347,9 +347,9 @@ RPG 创作工作台、拼图创作工作台、大鱼吃小鱼创作工作台都
- 世界框架 - 世界框架
- ThemePack - ThemePack
- StoryGraph 的基础版 - StoryGraph 的基础版
- 百梦主锚点摘要 - 陶泥儿主锚点摘要
这一层完成后,系统应能让百梦主看到: 这一层完成后,系统应能让陶泥儿主看到:
- 世界现在到底被理解成了什么 - 世界现在到底被理解成了什么
- 哪些冲突 / 势力 / 意象被识别出来了 - 哪些冲突 / 势力 / 意象被识别出来了
@@ -362,11 +362,11 @@ RPG 创作工作台、拼图创作工作台、大鱼吃小鱼创作工作台都
- 关键场景角色 - 关键场景角色
- 关键地点 - 关键地点
这一层优先围绕百梦主明确输入的角色和地点,而不是先铺满全部数量。 这一层优先围绕陶泥儿主明确输入的角色和地点,而不是先铺满全部数量。
### 第三层:百梦主校对层 ### 第三层:陶泥儿主校对层
在继续展开长尾内容前,应允许百梦主做一次轻量校对: 在继续展开长尾内容前,应允许陶泥儿主做一次轻量校对:
- 确认关键角色是否对 - 确认关键角色是否对
- 确认关键地点是否对 - 确认关键地点是否对
@@ -408,7 +408,7 @@ RPG 创作工作台、拼图创作工作台、大鱼吃小鱼创作工作台都
这样做的价值很高: 这样做的价值很高:
1. 降低首次等待焦虑 1. 降低首次等待焦虑
2.百梦主更早介入关键对象校正 2.陶泥儿主更早介入关键对象校正
3. 避免系统在创作方向还没稳定前,先铺满大量长尾内容 3. 避免系统在创作方向还没稳定前,先铺满大量长尾内容
## 5.4 角色与场景生成要改成“锚点优先 + 长尾补位” ## 5.4 角色与场景生成要改成“锚点优先 + 长尾补位”
@@ -417,11 +417,11 @@ RPG 创作工作台、拼图创作工作台、大鱼吃小鱼创作工作台都
优化后应改为: 优化后应改为:
1. 先生成百梦主明确指定的关键角色 / 地点 1. 先生成陶泥儿主明确指定的关键角色 / 地点
2. 再根据世界冲突自动补位缺失的角色原型和场景功能位 2. 再根据世界冲突自动补位缺失的角色原型和场景功能位
3. 最后再铺长尾 3. 最后再铺长尾
这样生成出来的世界会更像“围绕百梦主意图长出来”,而不是“先生成了一个完整世界,再让百梦主去认领” 这样生成出来的世界会更像“围绕陶泥儿主意图长出来”,而不是“先生成了一个完整世界,再让陶泥儿主去认领”
## 6. 结果页与编辑工作台优化方案 ## 6. 结果页与编辑工作台优化方案
@@ -439,7 +439,7 @@ RPG 创作工作台、拼图创作工作台、大鱼吃小鱼创作工作台都
优化后建议改成 4 层工作台: 优化后建议改成 4 层工作台:
1. 创作锚点 1. 创作锚点
- 展示百梦主输入和锁定内容 - 展示陶泥儿主输入和锁定内容
2. 关键对象 2. 关键对象
- 关键角色、关键地点、关键冲突对象 - 关键角色、关键地点、关键冲突对象
@@ -448,11 +448,11 @@ RPG 创作工作台、拼图创作工作台、大鱼吃小鱼创作工作台都
- AI 自动展开的长尾角色、长尾地点、补位内容 - AI 自动展开的长尾角色、长尾地点、补位内容
4. 世界编译摘要 4. 世界编译摘要
- 展示世界线程、题材包、运行时摘要,但默认不要求百梦主编辑 - 展示世界线程、题材包、运行时摘要,但默认不要求陶泥儿主编辑
## 6.2 编辑界面应遵守“高价值字段前置,低价值字段折叠” ## 6.2 编辑界面应遵守“高价值字段前置,低价值字段折叠”
百梦主默认暴露的应是: 陶泥儿主默认暴露的应是:
- 角色一句话定位 - 角色一句话定位
- 角色表面面貌 - 角色表面面貌
@@ -507,7 +507,7 @@ RPG 创作工作台、拼图创作工作台、大鱼吃小鱼创作工作台都
## 7.1 新增 `CustomWorldCreatorIntent` ## 7.1 新增 `CustomWorldCreatorIntent`
建议新增百梦主输入的统一结构: 建议新增陶泥儿主输入的统一结构:
```ts ```ts
interface CustomWorldCreatorIntent { interface CustomWorldCreatorIntent {
@@ -529,7 +529,7 @@ interface CustomWorldCreatorIntent {
作用: 作用:
- 把“百梦主真正输入了什么”从最终 `CustomWorldProfile` 中分离出来 - 把“陶泥儿主真正输入了什么”从最终 `CustomWorldProfile` 中分离出来
## 7.2 新增 `CustomWorldAnchorPack` ## 7.2 新增 `CustomWorldAnchorPack`
@@ -583,7 +583,7 @@ interface CustomWorldGenerationDraft {
作用: 作用:
- 让“百梦主输入、AI 编译、结果编辑”成为连续工作流,而不是只有最终成品对象 - 让“陶泥儿主输入、AI 编译、结果编辑”成为连续工作流,而不是只有最终成品对象
## 8. 与当前仓库的接入建议 ## 8. 与当前仓库的接入建议
@@ -597,7 +597,7 @@ interface CustomWorldGenerationDraft {
目标: 目标:
- 把单 textarea 升级为“快速模式 + 卡片模式” - 把单 textarea 升级为“快速模式 + 卡片模式”
- 新增百梦主意图状态 - 新增陶泥儿主意图状态
- 新增锁定和局部重生成入口 - 新增锁定和局部重生成入口
## 8.2 prompt 与生成服务层 ## 8.2 prompt 与生成服务层
@@ -623,7 +623,7 @@ interface CustomWorldGenerationDraft {
目标: 目标:
-`CustomWorldProfile` 增加百梦主意图与锚点相关扩展字段 -`CustomWorldProfile` 增加陶泥儿主意图与锚点相关扩展字段
- 保持旧档兼容 - 保持旧档兼容
- 让现有 builder 能同时消费 `creatorIntent + anchorPack + profile seed` - 让现有 builder 能同时消费 `creatorIntent + anchorPack + profile seed`
@@ -647,28 +647,28 @@ interface CustomWorldGenerationDraft {
本次优化不做以下事情: 本次优化不做以下事情:
1. 不推翻当前自定义世界最终输出仍是 `CustomWorldProfile` 的兼容目标 1. 不推翻当前自定义世界最终输出仍是 `CustomWorldProfile` 的兼容目标
2. 不把所有运行时结构都暴露给百梦主直接编辑 2. 不把所有运行时结构都暴露给陶泥儿主直接编辑
3. 不要求百梦主理解 `themePack / storyGraph / knowledgeFacts / threadContracts` 等系统结构 3. 不要求陶泥儿主理解 `themePack / storyGraph / knowledgeFacts / threadContracts` 等系统结构
4. 不把复杂数值平衡、掉落预算、build 预算转移给百梦 4. 不把复杂数值平衡、掉落预算、build 预算转移给陶泥儿
5. 不把“高自由度”理解成“所有字段都手工可改” 5. 不把“高自由度”理解成“所有字段都手工可改”
## 10. 验收标准 ## 10. 验收标准
做到以下几点,才算这次优化真正成立: 做到以下几点,才算这次优化真正成立:
1. 百梦主可以不用写长文,只靠卡片输入也能完成自定义世界创建。 1. 陶泥儿主可以不用写长文,只靠卡片输入也能完成自定义世界创建。
2. 系统会明确区分“百梦主锚点”和“AI 自动展开内容”。 2. 系统会明确区分“陶泥儿主锚点”和“AI 自动展开内容”。
3. 百梦主不再需要默认手改大量 `skills / initialItems / backstoryReveal / scene connections` 才能得到可用世界。 3. 陶泥儿主不再需要默认手改大量 `skills / initialItems / backstoryReveal / scene connections` 才能得到可用世界。
4. 结果页支持锁定关键角色、关键地点、关键冲突,并支持局部重生成。 4. 结果页支持锁定关键角色、关键地点、关键冲突,并支持局部重生成。
5. 重新生成不再默认覆盖整个世界。 5. 重新生成不再默认覆盖整个世界。
6. 当前 `framework -> themePack -> storyGraph -> role/landmark` 生成主链可以继续复用,而不是被废弃。 6. 当前 `framework -> themePack -> storyGraph -> role/landmark` 生成主链可以继续复用,而不是被废弃。
7. 结果页默认展示的是高创作价值对象,而不是系统级低层字段。 7. 结果页默认展示的是高创作价值对象,而不是系统级低层字段。
8. 长尾内容生成明显后置于关键对象生成,百梦主能更早看到并修正关键对象。 8. 长尾内容生成明显后置于关键对象生成,陶泥儿主能更早看到并修正关键对象。
9. 旧的自由文本输入模式仍然可用,但不再是唯一入口。 9. 旧的自由文本输入模式仍然可用,但不再是唯一入口。
## 11. 推荐落地顺序 ## 11. 推荐落地顺序
## 阶段 A先加百梦主意图层 ## 阶段 A先加陶泥儿主意图层
先做: 先做:
@@ -678,7 +678,7 @@ interface CustomWorldGenerationDraft {
目标: 目标:
- 先把百梦主输入从“单一大文本”升级成“可识别的创作锚点” - 先把陶泥儿主输入从“单一大文本”升级成“可识别的创作锚点”
## 阶段 B再加锚点包与锁定能力 ## 阶段 B再加锚点包与锁定能力
@@ -721,4 +721,4 @@ interface CustomWorldGenerationDraft {
当前自定义世界流程最需要优化的,不是“让 AI 再多生成一点内容”,而是: 当前自定义世界流程最需要优化的,不是“让 AI 再多生成一点内容”,而是:
**把百梦主从低价值字段编辑里解放出来,让百梦主负责世界灵魂锚点,让 AI 负责围绕这些锚点分层生成、分层展开、分层可控地把世界长出来。** **把陶泥儿主从低价值字段编辑里解放出来,让陶泥儿主负责世界灵魂锚点,让 AI 负责围绕这些锚点分层生成、分层展开、分层可控地把世界长出来。**

View File

@@ -16,7 +16,7 @@
## 1. 一句话定义 ## 1. 一句话定义
百梦主在创作页通过表单确认题材主题和难度选项,系统根据难度选项派生需要消除次数与难度数值,并编译出一个可试玩、可发布的单局抓大鹅玩法作品;玩家在 `10` 分钟倒计时内点击圆形空间中可见物品,把物品放入下方 `7` 格备选栏,每凑齐 `3` 个同物品 id 自动消除,最终清空圆形空间内全部物品即胜利。 陶泥儿主在创作页通过表单确认题材主题和难度选项,系统根据难度选项派生需要消除次数与难度数值,并编译出一个可试玩、可发布的单局抓大鹅玩法作品;玩家在 `10` 分钟倒计时内点击圆形空间中可见物品,把物品放入下方 `7` 格备选栏,每凑齐 `3` 个同物品 id 自动消除,最终清空圆形空间内全部物品即胜利。
--- ---
@@ -96,22 +96,23 @@ Match3D 必须形成独立玩法域,后续技术方案至少需要覆盖:
2. 创建流程采用入口表单收集关键配置。 2. 创建流程采用入口表单收集关键配置。
3. 表单必须在进入结果页前确认: 3. 表单必须在进入结果页前确认:
- 题材主题 - 题材主题
- 3D 素材风格 - 2D 素材风格
- 难度选项 - 难度选项
4. `需要消除次数` 与难度 `1~10` 数值不再作为独立输入框展示,由难度选项派生。 4. `需要消除次数` 与难度 `1~10` 数值不再作为独立输入框展示,由难度选项派生。
5. 生成抓大鹅草稿消耗 `20` 点,生成按钮必须显式展示。 5. 生成抓大鹅草稿固定消耗 `10` 点,生成按钮必须显式展示。
6. 结果页支持编辑游戏名称、标签、封面图等基础发布信息 6. 结果页背景音乐重新生成固定消耗 `5` 泥点UI 背景重新生成固定消耗 `2` 泥点;批量新增物品素材按实际可新增物品名每 `5` 个消耗 `2` 泥点,不足 `5` 个向上取整
7. 发布前支持试玩,并允许随时停止和修改配置 7. 结果页支持编辑游戏名称、标签、封面图等基础发布信息
8. 发布不要求试玩通关 8. 发布前支持试玩,并允许随时停止和修改配置
9. 单局运行态使用 `10` 分钟倒计时 9. 发布不要求试玩通关
10. 下方备选栏固定为 `7` 个格子 10. 单局运行态使用 `10` 分钟倒计时
11. 玩家点击可见物品后,物品飞入备选栏 11. 下方备选栏固定为 `7` 个格子
12. 备选栏中每凑齐 `3` 个相同物品 id 自动消除 12. 玩家点击可见物品后,物品飞入备选栏。
13. 清空圆形空间中全部物品即胜利 13. 备选栏中每凑齐 `3` 个相同物品 id 自动消除
14. 倒计时结束或备选栏满即失败 14. 清空圆形空间中全部物品即胜利
15. 胜利 / 失败后展示结算界面 15. 倒计时结束或备选栏满即失败
16. 入口页的 3D 素材风格选择会进入素材图提示词,并作为结果页手动 Rodin 3D 模型生成的默认提示词依据 16. 胜利 / 失败后展示结算界面
17. 点击、入槽、消除、失败、胜利的即时反馈效果由前端先行呈现,后端负责权威确认、状态落库和成绩可信性 17. 入口页的 2D 素材风格选择会进入素材图提示词,并作为后续物品素材新增和重绘的默认提示词依据
18. 点击、入槽、消除、失败、胜利的即时反馈效果由前端先行呈现,后端负责权威确认、状态落库和成绩可信性。
--- ---
@@ -124,7 +125,7 @@ Match3D 必须形成独立玩法域,后续技术方案至少需要覆盖:
3. 不做排行榜正式展示。 3. 不做排行榜正式展示。
4. 不做道具,但需要预留功能口。 4. 不做道具,但需要预留功能口。
5. 不做洗牌、重置、旋转、放大等局内操作。 5. 不做洗牌、重置、旋转、放大等局内操作。
6. 不做多批次真实 3D 模型生成;当前草稿生成只固定产出 `3` 个 GLB 模型并写入 OSS。 6. 不做首屏真实 3D 模型生成;当前草稿生成以多视角 2D 物品素材为主,并写入 OSS。
7. 不做真实 3D 物理遮挡。 7. 不做真实 3D 物理遮挡。
8. 不做真实物理碰撞结算。 8. 不做真实物理碰撞结算。
9. 不做必须试玩通关才能发布的门槛。 9. 不做必须试玩通关才能发布的门槛。
@@ -143,7 +144,7 @@ Match3D 首版参考拼图后期的入口表单收集方式,而不是早期的
表单的职责是帮助用户确认可以直接编译 demo 的最小配置: 表单的职责是帮助用户确认可以直接编译 demo 的最小配置:
1. 题材主题。 1. 题材主题。
2. 3D 素材风格。 2. 2D 素材风格。
3. 游戏难度选项。 3. 游戏难度选项。
`需要消除次数` 与游戏难度数值仍属于后端会话配置,但不再要求用户手填。当前入口页固定采用以下映射: `需要消除次数` 与游戏难度数值仍属于后端会话配置,但不再要求用户手填。当前入口页固定采用以下映射:
@@ -152,7 +153,7 @@ Match3D 首版参考拼图后期的入口表单收集方式,而不是早期的
轻松 -> 需要消除 8 次,难度 2 轻松 -> 需要消除 8 次,难度 2
标准 -> 需要消除 12 次,难度 4 标准 -> 需要消除 12 次,难度 4
进阶 -> 需要消除 16 次,难度 6 进阶 -> 需要消除 16 次,难度 6
硬核 -> 需要消除 20 次,难度 8 硬核 -> 需要消除 21 次,难度 8
``` ```
## 6.2 必填配置 ## 6.2 必填配置
@@ -161,7 +162,7 @@ Match3D 首版参考拼图后期的入口表单收集方式,而不是早期的
题材决定后续生成或选择物品素材的方向。用户可以自定义主题,例如水果、玩具、食物、符号等。 题材决定后续生成或选择物品素材的方向。用户可以自定义主题,例如水果、玩具、食物、符号等。
当前抓大鹅草稿生成会固定生成 `3` 个题材物品:素材图切割出的独立图片会作为 Rodin 图生 3D 参考图,生成出的 GLB 模型必须转存 OSS并随作品 profile 的 `generatedItemAssets` 持久化。运行态优先使用这些生成模型;只有模型缺失、加载失败或未进入 3D 渲染模式时,才回退到 25 个默认积木件视觉键。默认素材不使用透明气泡,也不在图案上放文字标识。 当前抓大鹅草稿会按难度生成题材物品:素材图切割出的多视角 2D 图片必须转存 OSS并随作品 profile 的 `generatedItemAssets` 持久化。运行态优先使用这些生成图片;只有图片缺失、读取失败或未进入生成素材模式时,才回退到默认积木件视觉键。默认素材不使用透明气泡,也不在图案上放文字标识。
可消除物尺寸使用五档相对体积规则XL 型相对体积为 `1.60~2.30`L 型为 `1.25~1.60`M 型为 `1.00`XS 型为 `0.65~0.85`S 型为 `0.35~0.50`。单局中 XL / L / M / XS / S 按本局使用的消除物类型数的 `20% / 30% / 30% / 15% / 5%` 分配;非整数配额按最大余数补齐,确保总数等于本局使用类型数量。同一关卡内同一个颜色和造型的物品只能对应一个尺寸档位;可存在同尺寸但不同颜色和造型的物品。后端运行态通过 `radius` 下发权威尺寸,前端只按快照表现。 可消除物尺寸使用五档相对体积规则XL 型相对体积为 `1.60~2.30`L 型为 `1.25~1.60`M 型为 `1.00`XS 型为 `0.65~0.85`S 型为 `0.35~0.50`。单局中 XL / L / M / XS / S 按本局使用的消除物类型数的 `20% / 30% / 30% / 15% / 5%` 分配;非整数配额按最大余数补齐,确保总数等于本局使用类型数量。同一关卡内同一个颜色和造型的物品只能对应一个尺寸档位;可存在同尺寸但不同颜色和造型的物品。后端运行态通过 `radius` 下发权威尺寸,前端只按快照表现。
@@ -183,19 +184,27 @@ Match3D 首版参考拼图后期的入口表单收集方式,而不是早期的
首版 demo 中,用户只需凭感觉选择难度;具体难度规则由系统内部解释。后续优化阶段再细化难度曲线、生成算法和遮挡策略。 首版 demo 中,用户只需凭感觉选择难度;具体难度规则由系统内部解释。后续优化阶段再细化难度曲线、生成算法和遮挡策略。
### 3D 素材风格 ### 2D 素材风格
入口页在题材主题与难度之间展示 `3D素材风格` 横向滑动选择。首批固定选项为: 入口页在题材主题与难度之间展示 `2D素材风格` 横向滑动选择。首批固定选项为:
```text ```text
黏土手作 / 低多边形 / 玩具塑料 / 木质雕刻 / 体素积木 / 金属机甲 / 自定义 扁平图标 / 赛璐璐卡通 / 像素复古 / 手绘水彩 / 贴纸描边 / 厚涂图标 / 自定义
``` ```
每个内置选项使用 VectorEngine `gpt-image-2-all` 生成的画风参考图展示;参考图保存在 `public/match3d-style-references/`,只作为入口选择的视觉提示,不作为用户上传参考图。选择内置风格时,前端提交 `assetStyleId``assetStyleLabel` 与对应 `assetStylePrompt`。选择 `自定义` 时必须弹出独立面板,用户填写描述后才允许应用;自定义描述作为 `assetStylePrompt` 进入后端生成链路。 每个内置选项使用 VectorEngine `gpt-image-2-all` 生成的画风参考图展示;参考图保存在 `public/match3d-style-references/`,只作为入口选择的视觉提示,不作为用户上传参考图。每张参考图只展示 `1` 个完整独立物品,不能展示 `5` 个物品样张或多物品散点图,避免用户误判为物品数量配置。选择内置风格时,前端提交 `assetStyleId``assetStyleLabel` 与对应 `assetStylePrompt`。选择 `自定义` 时必须弹出独立面板,用户填写描述后才允许应用;自定义描述作为 `assetStylePrompt` 进入后端生成链路。
`像素复古``assetStylePrompt` 必须是强约束而不是泛化描述:真正复古像素 2D 游戏道具 sprite先按约 `64x64` 低分辨率像素块绘制再整数倍放大,硬边方块像素清晰可见,有限色板 `12-24` 色,并禁止抗锯齿、柔焦、平滑渐变、真实 3D 渲染、PBR 材质和摄影光照。后端收到 `assetStyleId = pixel-retro` 时必须兜底补齐这组约束。
## 6.3 参考图片 ## 6.3 参考图片
抓大鹅入口页不展示参考图片上传。题材表现由题材文本和草稿切割图片链路承接;草稿生成阶段会直接以切割图片作为 Rodin 图生模型参考图生成首批 GLB。结果页 `3D素材` Tab 仍可对单个素材触发重新生成 抓大鹅入口页不展示参考图片上传。题材表现由题材文本和草稿切割图片链路承接;草稿生成阶段会生成多视角 2D 物品素材并写入作品 profile。结果页 `素材配置 > 物品` 继续承接物品素材预览、删除、批量新增和音效配置
## 6.4 生成音效入口
抓大鹅入口页不展示 `生成音效` Toggle。草稿生成阶段只保存 `generatedItemAssets[].soundPrompt`,不调用 Vidu 生成点击音效,也不产生点击音效相关扣费。
结果页仍保留单个物品音效的手动补生成入口。用户在 `素材配置 > 物品` 详情面板中生成点击音效时,后端复用通用创作音频接口和资产落点,把结果写入对应 `generatedItemAssets[].clickSound`
--- ---
@@ -222,9 +231,15 @@ Match3D 首版参考拼图后期的入口表单收集方式,而不是早期的
## 7.3 素材生成边界 ## 7.3 素材生成边界
抓大鹅草稿生成链路会生成首批 `3`题材物品素材文本模型生成物品名VectorEngine 生成 `2*2` 素材图并切割独立图片,再以每张独立图片调用 Rodin 图生 3D下载 `.glb` 并转存 OSS。入口页选择的 `assetStylePrompt` 必须写入素材图提示词;结果页手动 Rodin 图生模型时,继续以该物品图片和默认提示词作为起点。 抓大鹅草稿生成链路会根据难度生成题材物品素材文本模型生成物品名VectorEngine 分批生成 `1:1` 素材图并切割为每个物品 `5` 张不同视角图片,再转存 OSS。实际生成数量必须向上补齐为 `5` 的倍数,并生成补齐物品的名称和对应图片;例如标准难度玩法使用 `9` 种物品,但素材实际生成 `10`。入口页选择的 `assetStylePrompt` 必须写入素材图提示词;结果页批量新增物品时继续以该风格作为默认提示词起点。
生成出的独立图片与 GLB 模型都必须作为草稿页 `3D素材` Tab 的预览资产返回。模型生成成功时 `generatedItemAssets[].status = model_ready`,并携带 `modelSrc``modelObjectKey``modelFileName``taskUuid``subscriptionKey`;正式平台资产绑定和更完整的二次编辑流程以后续技术方案为准 批量新增物品素材与草稿生成使用同一素材图处理流程:先按用户实际新增名称补齐到 `5` 的倍数,整图生成完成后丢弃补齐用临时物品,只对用户实际新增项继续绿幕抠背景、切割和 OSS 上传,并只把这些真实新增物品写入 `generatedItemAssets`;补齐用临时物品不进入作品资产列表、不参与发布校验和运行态映射。计费数量按清洗、去重、排除已有物品并截断到容量上限后的实际新增数量计算
素材图提示词必须固定要求 `5*5` 严格均匀排布,每格主体完整居中,不得跨格、贴边或越界,避免切割成独立图片后出现相邻物品内容污染。
生成出的独立图片必须作为结果页 `素材配置 > 物品` 的预览资产返回。图片素材生成成功时 `generatedItemAssets[].status = image_ready`,并携带 `imageViews[]`,兼容字段 `imageSrc` / `imageObjectKey` 指向首张视角图;正式平台资产绑定和更完整的二次编辑流程以后续技术方案为准。
局内 UI 生成分为两类图片:`9:16` 纯背景图和 `1:1` 中心容器 UI 图。纯背景图只表现题材氛围和环境不得生成锅、圆盘、托盘、拼图槽、物品槽、HUD、文字、按钮、倒计时、分数或物品中心容器 UI 图单独生成,贴合题材设定,用于覆盖运行态默认圆形竞技容器。容器图必须参考 `public/match3d-background-references/pot-fused-reference.png` 的大尺寸轻俯视构图:容器外轮廓接近画布四边,宽度约占画布 `86%-92%`、高度约占 `82%-90%`,内口为横向椭圆,不能生成小圆盘、正俯视扁盘、侧视碗或小托盘。底部备选栏、顶部控件和拼图/物品槽位继续使用运行态默认 UI不烘进生成背景。
## 7.4 发布前试玩 ## 7.4 发布前试玩
@@ -261,8 +276,8 @@ Match3D 首版参考拼图后期的入口表单收集方式,而不是早期的
运行时主交互空间是一个有边界的圆形空间。 运行时主交互空间是一个有边界的圆形空间。
1. 圆形空间使用俯视角。 1. 圆形空间使用俯视角。
2. 背景环境资源后续可以尝试伪 3D 视角效果 2. 背景环境资源只作为纯背景层,不承接圆形空间边界
3. 圆形空间边界是中间交互图案的边界 3. 圆形空间边界由运行态默认容器或生成出的中心容器 UI 图承接,不能烘进纯背景图
4. 物品不能超出圆形边界,也不能被边界压住或裁切。 4. 物品不能超出圆形边界,也不能被边界压住或裁切。
5. 运行态快照中的 `x / y / radius` 使用前端可直接渲染的 `0~1` 归一化坐标;圆心固定为 `(0.5, 0.5)`,圆形可用半径为 `0.5` 5. 运行态快照中的 `x / y / radius` 使用前端可直接渲染的 `0~1` 归一化坐标;圆心固定为 `(0.5, 0.5)`,圆形可用半径为 `0.5`
6. 后端生成和前端兜底渲染都必须满足 `distance((x, y), (0.5, 0.5)) + radius <= 0.5 - safeMargin``safeMargin` 至少覆盖圆形边框和视觉阴影,避免可消除图案贴边裁切。 6. 后端生成和前端兜底渲染都必须满足 `distance((x, y), (0.5, 0.5)) + radius <= 0.5 - safeMargin``safeMargin` 至少覆盖圆形边框和视觉阴影,避免可消除图案贴边裁切。
@@ -277,13 +292,16 @@ totalItemCount = clearCount * 3
每种物品数量必须是 `3` 的倍数,避免生成无法通关的局。 每种物品数量必须是 `3` 的倍数,避免生成无法通关的局。
生成的消除物类型数由用户填写的需要消除次数决定: 生成的消除物类型数由难度档位决定:
```text ```text
itemTypeCount = clearCount <= 25 ? clearCount : 25 轻松 = 3
标准 = 9
进阶 = 15
硬核 = 21
``` ```
`clearCount <= 25` 时,本局生成的 `itemTypeId` 数量等于 `clearCount`,每种类型默认生成 `3` 件;当 `clearCount > 25` 时,本局最多生成 `25` `itemTypeId`,后续消除组按这 `25`类型轮转补齐,且每种类型最终数量仍必须保持 `3` 的倍数 前四档难度分别生成 `3 / 9 / 15 / 21` `itemTypeId`。历史草稿若仍保留 `clearCount = 20` 的硬核配置,运行时和素材生成都必须兼容映射为 `21`物品,不得回退成 `20` 种。
同一局内这些类型必须分别使用不同的形状和颜色组合,不能出现两个组看起来像同一种物体的情况。 同一局内这些类型必须分别使用不同的形状和颜色组合,不能出现两个组看起来像同一种物体的情况。
@@ -297,13 +315,13 @@ itemTypeCount = clearCount <= 25 ? clearCount : 25
## 8.5 物品资产 ## 8.5 物品资产
当前 demo 使用生成 GLB 优先、默认积木兜底的物品资产策略。 当前 demo 使用生成 2D 图片优先、默认积木兜底的物品资产策略。
1. demo 至少提供 `25` 种彼此不同的颜色与几何造型组合默认素材,支撑 `clearCount > 25` 时的类型上限和 GLB 缺失兜底。 1. demo 至少提供 `25` 种彼此不同的颜色与几何造型组合默认素材,支撑 `clearCount > 25` 时的类型上限和图片缺失兜底。
2.`generatedItemAssets[].modelSrc``modelObjectKey` 时,运行态与备选栏必须优先读取该 GLB;默认积木件只作为加载失败、模型缺失或 2D 回退时的兜底素材池。 2.`generatedItemAssets[].imageViews``imageSrc``imageObjectKey` 时,运行态与备选栏必须优先读取该 2D 图片素材;默认积木件只作为加载失败或图片缺失时的兜底素材池。
3. 前端读取生成模型必须通过 `/api/assets/read-bytes` 获取私有 OSS 字节,再交给 Three.js `GLTFLoader` 解析;不得直接把 `/generated-match3d-assets/...` 当裸 URL 请求。 3. 前端读取 generated legacy 图片必须通过 `/api/assets/read-url` 换签后加载;不得直接把 `/generated-match3d-assets/...` 当裸 URL 请求。
4. 当前固定 `clearCount = 3` 的生成草稿中,运行态 `match3d-type-01/02/03` 按类型编号顺序映射到生成出的 `3` 个模型;后续恢复更大生成数量时,模型列表顺序必须继续与类型编号稳定对应。 4. 运行态 `match3d-type-01/02/03` 等类型按类型编号顺序映射到生成出的图片素材列表;后续更大生成数量时,素材列表顺序必须继续与类型编号稳定对应。
5. 默认积木视觉键仍需映射为无文字的纯色 2D 图标和程序化 3D 积木模型,不能显示为透明气泡或文字标记。 5. 默认积木视觉键仍需映射为无文字的纯色 2D 图标,不能显示为透明气泡或文字标记。
6. 用户题材主题后续会映射为符合常识预期的物品集合。 6. 用户题材主题后续会映射为符合常识预期的物品集合。
示例:水果题材可以对应红色苹果、黄色香蕉、紫色葡萄等。 示例:水果题材可以对应红色苹果、黄色香蕉、紫色葡萄等。
@@ -334,7 +352,7 @@ itemTypeCount = clearCount <= 25 ? clearCount : 25
飞行动画过程中,物品不再与其他物品产生碰撞。 飞行动画过程中,物品不再与其他物品产生碰撞。
当前 3D 实验模式下,物品进入备选栏后必须从圆形空间的物理世界移除;备选栏展示该物品同款 3D 模型的独立预览,固定为斜 `45` 度便于识别,不再参与场内碰撞、重力或堆叠。 物品进入备选栏后必须从圆形空间的可点击列表移除;备选栏展示该物品同款 2D 素材图,不再参与场内点击、遮挡或堆叠。
前端播放即时反馈的同时,必须向后端提交点击意图。后端确认后固化入槽结果;后端拒绝时,前端恢复物品位置和备选栏表现。 前端播放即时反馈的同时,必须向后端提交点击意图。后端确认后固化入槽结果;后端拒绝时,前端恢复物品位置和备选栏表现。
@@ -344,7 +362,7 @@ itemTypeCount = clearCount <= 25 ? clearCount : 25
1. 每次点击进入即时反馈流程后,前端先把物品表现为进入备选栏。 1. 每次点击进入即时反馈流程后,前端先把物品表现为进入备选栏。
2. 备选栏中每出现 `3` 个相同物品 id前端立即播放自动消除效果并腾出格子。 2. 备选栏中每出现 `3` 个相同物品 id前端立即播放自动消除效果并腾出格子。
3. 3D 模式下,备选栏格子展示从场内取出的同款 3D 模型预览,视角固定斜 `45` 度,不使用另一套不一致的 UI 图标;托盘预览必须共享一个 WebGL renderer并按 `7` 格容器实际宽高把模型居中摆放到对应格子不能因多个预览上下文导致中心场地模型不可见WebGL 回退或 `2D` 模式下才使用保留的 2D 图标。 3. 备选栏格子展示从场内取出的同款 2D 素材图,不使用另一套不一致的 UI 图标;图片缺失或读取失败时才使用保留的默认图标。
4. 后端确认后固化真实备选栏和消除结果;若后端返回状态不一致,前端必须以最新后端快照校正。 4. 后端确认后固化真实备选栏和消除结果;若后端返回状态不一致,前端必须以最新后端快照校正。
5. 如果备选栏满且无法消除,前端可以立即展示失败过渡,最终失败状态以后端确认为准。 5. 如果备选栏满且无法消除,前端可以立即展示失败过渡,最终失败状态以后端确认为准。
@@ -674,7 +692,7 @@ GET /api/runtime/match3d/runs/:runId
入口表单只展示三个输入块: 入口表单只展示三个输入块:
1. `想做一个什么题材的抓大鹅?` 大文本输入框。 1. `想做一个什么题材的抓大鹅?` 大文本输入框。
2. `3D素材风格` 横向滑动风格卡,最后一个为 `自定义` 2. `2D素材风格` 横向滑动风格卡,最后一个为 `自定义`
3. `难度` 选项按钮。 3. `难度` 选项按钮。
入口页不展示参考图、`需要消除次数` 数值输入、`难度数值` 滑杆,也不展示 `题材 / 物品 / 难度` 三个摘要框。`需要消除次数``difficulty` 由难度选项派生后提交给后端。 入口页不展示参考图、`需要消除次数` 数值输入、`难度数值` 滑杆,也不展示 `题材 / 物品 / 难度` 三个摘要框。`需要消除次数``difficulty` 由难度选项派生后提交给后端。
@@ -685,6 +703,8 @@ GET /api/runtime/match3d/runs/:runId
结果页保持清爽,复用平台已有作品结果页风格。 结果页保持清爽,复用平台已有作品结果页风格。
结果页 `难度配置` 中的四档难度使用横向离散拖动条呈现,拖动条只允许停在 `轻松 / 标准 / 进阶 / 硬核` 四个刻度上,刻度标签可点击切换,仍按同一映射派生 `需要消除次数``difficulty``物品种类`
点击按钮弹出独立面板时,不实现成在当前面板下面展开内容。 点击按钮弹出独立面板时,不实现成在当前面板下面展开内容。
## 14.4 运行态 ## 14.4 运行态
@@ -704,24 +724,25 @@ GET /api/runtime/match3d/runs/:runId
首版 PRD 对应 demo 验收标准: 首版 PRD 对应 demo 验收标准:
1. 用户可从平台创作入口进入“抓大鹅”模板。 1. 用户可从平台创作入口进入“抓大鹅”模板。
2. 入口表单能确认题材主题、3D 素材风格和难度选项,并提交派生后的消除次数与难度数值。 2. 入口表单能确认题材主题、2D 素材风格和难度选项,并提交派生后的消除次数与难度数值。
3. 入口页不展示参考图上传。 3. 入口页不展示参考图上传。
4. 内置风格显示画风参考图,自定义风格通过独立面板填写并进入提交 payload。 4. 内置风格显示画风参考图,自定义风格通过独立面板填写并进入提交 payload。
5. 移动端入口页所有内容一屏展示,不产生纵向滚动。 5. 移动端入口页所有内容一屏展示,不产生纵向滚动。
6. 系统可生成待发布结果页,并在草稿中返回首批切割图片与 OSS GLB 模型素材预览 6. 入口页不展示 `生成音效` Toggle草稿生成不产生 `clickSound`,结果页物品详情仍可手动生成点击音效
7. 用户可编辑游戏名称、标签、封面图等基础信息 7. 系统可生成待发布结果页,并在草稿中返回首批多视角 2D 切割图片素材预览
8. 用户可发布前试玩,且试玩失败不阻断发布 8. 用户可编辑游戏名称、标签、封面图等基础信息
9. 运行态能展示圆形空间、倒计时、物品和 `7` 格备选栏;存在 `generatedItemAssets` 模型时必须优先展示生成 GLB而不是默认积木素材 9. 用户可发布前试玩,且试玩失败不阻断发布
10. 物品可重叠、遮挡、堆叠 10. 运行态能展示圆形空间、倒计时、物品和 `7` 格备选栏;存在 `generatedItemAssets` 图片素材时必须优先展示生成 2D 素材,而不是默认积木素材
11. 被完全遮挡物品不可点击,露出可点击区域的物品可点击 11. 物品可重叠、遮挡、堆叠
12. 点击通过后物品飞入备选栏 12. 被完全遮挡物品不可点击,露出可点击区域的物品可点击。
13. 备选栏`3` 个相同物品 id 自动消除 13. 点击通过后物品飞入备选栏。
14. 清空空间中全部物品后胜利 14. 备选栏中 `3` 个相同物品 id 自动消除
15. 倒计时结束或备选栏满后失败 15. 清空空间中全部物品后胜利
16. 胜利结算展示使用时间 16. 倒计时结束或备选栏满后失败
17. 失败结算展示完成进度和重新开始按钮 17. 胜利结算展示使用时间
18. 局内即时反馈由前端先行呈现,关键状态以后端确认快照校正 18. 失败结算展示完成进度和重新开始按钮
19. 相关中文文档通过编码检查 19. 局内即时反馈由前端先行呈现,关键状态以后端确认快照校正
20. 相关中文文档通过编码检查。
--- ---

View File

@@ -13,7 +13,7 @@
-> 选择“拼图玩法” -> 选择“拼图玩法”
-> Agent 聊天收束高杠杆锚点 -> Agent 聊天收束高杠杆锚点
-> 生成拼图结果页 -> 生成拼图结果页
-> 百梦主生成并确认拼图图片 -> 陶泥儿主生成并确认拼图图片
-> 发布到拼图广场 -> 发布到拼图广场
-> 玩家从广场进入第 1 关 -> 玩家从广场进入第 1 关
-> 全屏拼图运行时 -> 全屏拼图运行时
@@ -26,7 +26,7 @@
## 1. 一句话定义 ## 1. 一句话定义
百梦主通过 Agent 对话确定拼图作品的高杠杆视觉锚点再由系统生成结果页、AI 生成拼图图片并发布到广场;玩家进入游戏后,在全屏拼图画布中通过交换、合并、拖动和拆分完成关卡,并沿着“相似题材优先、同作者次优先”的关卡链持续游玩。 陶泥儿主通过 Agent 对话确定拼图作品的高杠杆视觉锚点再由系统生成结果页、AI 生成拼图图片并发布到广场;玩家进入游戏后,在全屏拼图画布中通过交换、合并、拖动和拆分完成关卡,并沿着“相似题材优先、同作者次优先”的关卡链持续游玩。
--- ---
@@ -78,7 +78,7 @@
- 拼图关卡名 - 拼图关卡名
- AI 生成拼图图片的功能 - AI 生成拼图图片的功能
- 图片题材标签 - 图片题材标签
4. 百梦主发布后的拼图作品必须进入平台广场。 4. 陶泥儿主发布后的拼图作品必须进入平台广场。
5. 玩家从广场进入某个作品时,第 1 关必须先显示当前作品本身。 5. 玩家从广场进入某个作品时,第 1 关必须先显示当前作品本身。
6. 第 2 关及以后必须按照“标签相似度权重 `70%` + 同作者权重 `30%`”选择下一关。 6. 第 2 关及以后必须按照“标签相似度权重 `70%` + 同作者权重 `30%`”选择下一关。
7. 游戏运行时必须全屏展示拼图画布。 7. 游戏运行时必须全屏展示拼图画布。
@@ -129,7 +129,7 @@
创建拼图作品 创建拼图作品
-> Agent 聊天收束 5 个视觉锚点 -> Agent 聊天收束 5 个视觉锚点
-> 生成结果页 -> 生成结果页
-> 百梦主确认关卡名、标签、图片 -> 陶泥儿主确认关卡名、标签、图片
-> 发布到拼图广场 -> 发布到拼图广场
``` ```
@@ -137,12 +137,12 @@
### 5.1.1 已发布作品二次编辑 ### 5.1.1 已发布作品二次编辑
百梦主在“我的创作”中点击自己已发布的拼图作品时,不进入只读详情页,而是回到该作品绑定的拼图结果页继续编辑。独立的“体验”按钮仍然直接进入第 1 关,不与编辑入口混用。 陶泥儿主在“我的创作”中点击自己已发布的拼图作品时,不进入只读详情页,而是回到该作品绑定的拼图结果页继续编辑。独立的“体验”按钮仍然直接进入第 1 关,不与编辑入口混用。
落地规则: 落地规则:
1. 已发布拼图作品必须优先通过 `sourceSessionId` 恢复原 Agent session。 1. 已发布拼图作品必须优先通过 `sourceSessionId` 恢复原 Agent session。
2. 恢复后的结果页沿用原草稿、当前正式图、标题、摘要和标签;百梦主可以继续改标题、摘要、标签,并重新生成图片。 2. 恢复后的结果页沿用原草稿、当前正式图、标题、摘要和标签;陶泥儿主可以继续改标题、摘要、标签,并重新生成图片。
3. 再次点击发布时不得创建新作品,必须覆盖同一个 `profileId / workId` 3. 再次点击发布时不得创建新作品,必须覆盖同一个 `profileId / workId`
4. 覆盖发布只更新作品内容、更新时间、发布时间与广场投影;不得清零 `playCount`,不得改变作品归属。 4. 覆盖发布只更新作品内容、更新时间、发布时间与广场投影;不得清零 `playCount`,不得改变作品归属。
5. 如果历史作品缺少 `sourceSessionId`,前端只能退回作品详情,不伪造编辑 session。 5. 如果历史作品缺少 `sourceSessionId`,前端只能退回作品详情,不伪造编辑 session。
@@ -210,9 +210,9 @@
拼图 Agent 必须做到: 拼图 Agent 必须做到:
1. 优先接住百梦主的画面灵感,而不是立刻列问卷。 1. 优先接住陶泥儿主的画面灵感,而不是立刻列问卷。
2. 每轮只追问当前最影响图片生成质量的 `1` 个问题。 2. 每轮只追问当前最影响图片生成质量的 `1` 个问题。
3.百梦主已经说出足够信息时,优先总结,不重复追问。 3.陶泥儿主已经说出足够信息时,优先总结,不重复追问。
4. 当会话至少完成 `2` 轮后,工作区必须提供 `补充剩余关键字` 快捷动作。 4. 当会话至少完成 `2` 轮后,工作区必须提供 `补充剩余关键字` 快捷动作。
- 该动作沿用 RPG 聊天链路,仍走发送消息接口,但请求体必须携带 `quickFillRequested: true` - 该动作沿用 RPG 聊天链路,仍走发送消息接口,但请求体必须携带 `quickFillRequested: true`
- 前端不补数据、不伪造锚点状态,只发送“请补充剩余关键字。”作为本轮用户消息。 - 前端不补数据、不伪造锚点状态,只发送“请补充剩余关键字。”作为本轮用户消息。
@@ -255,7 +255,7 @@ interface PuzzleAnchorPack {
## 7.1 结果页定位 ## 7.1 结果页定位
拼图结果页是百梦主从 Agent 共创转入正式发布前的最小工作台。 拼图结果页是陶泥儿主从 Agent 共创转入正式发布前的最小工作台。
它至少承担 5 件事: 它至少承担 5 件事:
@@ -303,7 +303,7 @@ interface PuzzleAnchorPack {
关卡名生成规则建议如下: 关卡名生成规则建议如下:
1. 默认由 Agent 根据锚点自动生成 `1` 个正式候选名。 1. 默认由 Agent 根据锚点自动生成 `1` 个正式候选名。
2. 百梦主可直接手改。 2. 陶泥儿主可直接手改。
3. 关卡名长度建议控制在 `4~12` 个中文字符。 3. 关卡名长度建议控制在 `4~12` 个中文字符。
4. 不允许空标题发布。 4. 不允许空标题发布。
@@ -357,6 +357,7 @@ interface PuzzleAnchorPack {
4. 历史素材入口与添加参考图并列放在输入框右下角,打开独立素材选择面板,不在当前面板下方展开。 4. 历史素材入口与添加参考图并列放在输入框右下角,打开独立素材选择面板,不在当前面板下方展开。
5. UI 不默认写玩法规则说明,只展示必要状态、预览和操作。 5. UI 不默认写玩法规则说明,只展示必要状态、预览和操作。
6. 移动端中输入框右下角按钮必须可点且不遮挡正文输入;输入框需要预留底部内边距。 6. 移动端中输入框右下角按钮必须可点且不遮挡正文输入;输入框需要预留底部内边距。
7. 本地上传的非正方形拼图图片进入平台通用正方形图片裁剪弹窗;该弹窗的拖拽裁剪框、八向边界手柄、九宫格辅助线、遮罩和触控行为同时服务拼图图片上传与头像上传,后续不得在头像或拼图侧各自维护一套裁剪交互。
后端落地契约: 后端落地契约:
@@ -678,7 +679,7 @@ V1 规则如下:
1. 点击道具必须弹出独立确认窗口。 1. 点击道具必须弹出独立确认窗口。
2. 确认窗口期间暂停游戏时间。 2. 确认窗口期间暂停游戏时间。
3. 正式后端运行态每次确认消耗 `1` 点。 3. 正式后端运行态每次确认消耗 `1` 点。
4. 本地调试 run 不伪造钱包扣费,只保持确认、暂停和表现一致。 4. 本地调试 run 不伪造钱包扣费,只保持确认、暂停和表现一致。
--- ---
@@ -1160,7 +1161,7 @@ interface PuzzleRunSnapshot {
完成标准: 完成标准:
1. 百梦主能从平台进入拼图 Agent 工作区 1. 陶泥儿主能从平台进入拼图 Agent 工作区
2. 能通过聊天生成结果页草稿 2. 能通过聊天生成结果页草稿
## 阶段 B再做结果页与图片资产 ## 阶段 B再做结果页与图片资产
@@ -1174,7 +1175,7 @@ interface PuzzleRunSnapshot {
完成标准: 完成标准:
1. 百梦主能生成正式拼图图片并发布 1. 陶泥儿主能生成正式拼图图片并发布
2. 作品能进入拼图广场 2. 作品能进入拼图广场
## 阶段 C再做拼图运行时核心循环 ## 阶段 C再做拼图运行时核心循环
@@ -1232,4 +1233,4 @@ interface PuzzleRunSnapshot {
这次平台新增拼图玩法,正确的做法不是只补一个拼图画布,而是: 这次平台新增拼图玩法,正确的做法不是只补一个拼图画布,而是:
**把拼图作为平台内独立玩法类型接进现有 Agent-first 创作中心、结果页、发布链、广场分发链和运行时链,让百梦主先收束高杠杆视觉锚点,让玩家在全屏交换-合并-拆分的拼图循环中持续游玩。** **把拼图作为平台内独立玩法类型接进现有 Agent-first 创作中心、结果页、发布链、广场分发链和运行时链,让陶泥儿主先收束高杠杆视觉锚点,让玩家在全屏交换-合并-拆分的拼图循环中持续游玩。**

View File

@@ -630,7 +630,7 @@ SSE 事件:
1. 增加背景音乐和环境音,但不改变四帧三段主链。 1. 增加背景音乐和环境音,但不改变四帧三段主链。
2. 为移动端生成 `9:16` 竖版裁切版本。 2. 为移动端生成 `9:16` 竖版裁切版本。
3. 支持百梦主手动上传某张关键帧,再生成相邻视频。 3. 支持陶泥儿主手动上传某张关键帧,再生成相邻视频。
4. 支持发布后版本化替换开场动画。 4. 支持发布后版本化替换开场动画。
5. 支持用第四幕直接生成开局场景动态背景。 5. 支持用第四幕直接生成开局场景动态背景。
6. 支持把开场动画拆出的关键帧回流为作品详情页轮播素材。 6. 支持把开场动画拆出的关键帧回流为作品详情页轮播素材。

View File

@@ -22,7 +22,7 @@
接成一条新的稳定流程: 接成一条新的稳定流程:
**每个场景由百梦主在工具中配置为 `2~5` 幕;每一幕都绑定独立背景图和相遇 NPC 顺序;每一幕的第一个 NPC 视为主角色;运行时按幕切换背景和可遇对象,并根据主角色当前好感度裁决聊天轮数与第 5 轮收束方式。** **每个场景由陶泥儿主在工具中配置为 `2~5` 幕;每一幕都绑定独立背景图和相遇 NPC 顺序;每一幕的第一个 NPC 视为主角色;运行时按幕切换背景和可遇对象,并根据主角色当前好感度裁决聊天轮数与第 5 轮收束方式。**
本次还追加一条必须和草稿生成阶段一起落地的约束: 本次还追加一条必须和草稿生成阶段一起落地的约束:
@@ -31,13 +31,13 @@
补充口径修正: 补充口径修正:
1. `scene_chapter` 在本期继续保留为数据层 / 编译层 / 运行时层概念。 1. `scene_chapter` 在本期继续保留为数据层 / 编译层 / 运行时层概念。
2. `scene_chapter` 不作为百梦主可见的独立 Tab、独立卡片或独立导航入口。 2. `scene_chapter` 不作为陶泥儿主可见的独立 Tab、独立卡片或独立导航入口。
3. 百梦主配置多幕的唯一入口,是现有“场景”列表里的场景编辑弹层。 3. 陶泥儿主配置多幕的唯一入口,是现有“场景”列表里的场景编辑弹层。
4. 每一幕的 NPC 配置区必须直接叠在当前幕背景预览上,以“对面角色站位”的方式呈现;三个站位既是预览,也是编辑入口。 4. 每一幕的 NPC 配置区必须直接叠在当前幕背景预览上,以“对面角色站位”的方式呈现;三个站位既是预览,也是编辑入口。
5. 幕编辑站位中每个角色只显示角色形象与名称,不展示额外信息块、规则说明或说明性标签。 5. 幕编辑站位中每个角色只显示角色形象与名称,不展示额外信息块、规则说明或说明性标签。
6. 幕内小预览的构图固定为左侧玩家、右侧当前幕角色;右侧三个站位采用一前两后。 6. 幕内小预览的构图固定为左侧玩家、右侧当前幕角色;右侧三个站位采用一前两后。
前排主角色的 y 轴必须与玩家角色对齐后排两个角色必须同一列、x 轴对齐,上下分布,且后排整体的 y 轴中点与前排主角色保持一致。 前排主角色的 y 轴必须与玩家角色对齐后排两个角色必须同一列、x 轴对齐,上下分布,且后排整体的 y 轴中点与前排主角色保持一致。
7. 新建幕默认仅预置 1 个主角色槽位内容,其余槽位留空,等待百梦主补充。 7. 新建幕默认仅预置 1 个主角色槽位内容,其余槽位留空,等待陶泥儿主补充。
8. 角色名称显示在角色形象上方,角色渲染不附带方形 UI 底板。 8. 角色名称显示在角色形象上方,角色渲染不附带方形 UI 底板。
9. 世界档案的场景详情页不再单独展示“场景图片”和“场景内 NPC”字段相关兼容数据统一由多幕配置自动同步回场景对象。 9. 世界档案的场景详情页不再单独展示“场景图片”和“场景内 NPC”字段相关兼容数据统一由多幕配置自动同步回场景对象。
@@ -55,7 +55,7 @@
本次迭代必须同时满足以下目标: 本次迭代必须同时满足以下目标:
1. 百梦主可以在现有创作页面中为每个场景章节配置多幕内容。 1. 陶泥儿主可以在现有创作页面中为每个场景章节配置多幕内容。
2. 每一幕都必须绑定一张正式背景图。 2. 每一幕都必须绑定一张正式背景图。
3. 每一幕都可以配置玩家会遇到哪些 NPC并且保留顺序。 3. 每一幕都可以配置玩家会遇到哪些 NPC并且保留顺序。
4. 每一幕配置的第一个 NPC 必须被系统认定为该幕主角色。 4. 每一幕配置的第一个 NPC 必须被系统认定为该幕主角色。
@@ -89,7 +89,7 @@
1. 不新建独立的“场景编辑器”页面。 1. 不新建独立的“场景编辑器”页面。
2. 不把幕推进逻辑放到前端本地计算。 2. 不把幕推进逻辑放到前端本地计算。
3. 不让百梦主直接编辑底层运行时 `ChapterState` 或聊天状态对象。 3. 不让陶泥儿主直接编辑底层运行时 `ChapterState` 或聊天状态对象。
4. 不做多 NPC 并行聊天。 4. 不做多 NPC 并行聊天。
5. 不做每一幕的复杂分支树可视化编辑器。 5. 不做每一幕的复杂分支树可视化编辑器。
6. 不把“规则说明文案”默认堆到创作页或游戏 UI 面板里。 6. 不把“规则说明文案”默认堆到创作页或游戏 UI 面板里。
@@ -122,7 +122,7 @@
1. 场景章节没有“幕”这一层结构化对象。 1. 场景章节没有“幕”这一层结构化对象。
2. 背景图是场景级资产,不是幕级资产。 2. 背景图是场景级资产,不是幕级资产。
3. NPC 与场景的关系主要还是地点级归属,不是幕级相遇编排。 3. NPC 与场景的关系主要还是地点级归属,不是幕级相遇编排。
4. 百梦主无法在创作页里明确控制“这一幕谁先出场、谁是主角色”。 4. 陶泥儿主无法在创作页里明确控制“这一幕谁先出场、谁是主角色”。
## 4.2 游戏运行侧现状 ## 4.2 游戏运行侧现状
@@ -185,7 +185,7 @@
这意味着: 这意味着:
1. 百梦主在工具里编辑的是“第几幕”。 1. 陶泥儿主在工具里编辑的是“第几幕”。
2. 运行时仍然只认现有章节阶段枚举。 2. 运行时仍然只认现有章节阶段枚举。
3. `chapterDirector` 可以继续复用,只是数据来源从“纯 quest 推导”升级成“quest + 幕蓝图联合推导”。 3. `chapterDirector` 可以继续复用,只是数据来源从“纯 quest 推导”升级成“quest + 幕蓝图联合推导”。
@@ -214,7 +214,7 @@
- `name` - `name`
- `description` - `description`
- `imageSrc` - `imageSrc`
- `sceneNpcIds`(仅作为兼容字段,由多幕配置自动派生,不再作为百梦主可编辑字段) - `sceneNpcIds`(仅作为兼容字段,由多幕配置自动派生,不再作为陶泥儿主可编辑字段)
- `connections` - `connections`
- `sceneChapterBlueprints` 对应的多幕配置 - `sceneChapterBlueprints` 对应的多幕配置
2. 场景配置面板中,开局场景必须复用普通场景同级的配置 UI而不是继续保留一套缩水版表单。 2. 场景配置面板中,开局场景必须复用普通场景同级的配置 UI而不是继续保留一套缩水版表单。
@@ -251,7 +251,7 @@
原因: 原因:
1. 当前创作工作区已经进入“先收关键锚点、再逐步扩写”的阶段。 1. 当前创作工作区已经进入“先收关键锚点、再逐步扩写”的阶段。
2. 一次铺太多 playable、场景和长尾对象会稀释百梦主对第一版底稿的掌控感。 2. 一次铺太多 playable、场景和长尾对象会稀释陶泥儿主对第一版底稿的掌控感。
3. 本期还要把幕级背景图和角色主形象自动挂回草稿,如果对象规模不收束,等待时间和生成成本都会直接失控。 3. 本期还要把幕级背景图和角色主形象自动挂回草稿,如果对象规模不收束,等待时间和生成成本都会直接失控。
### 5.5.2 幕级出演角色与背景必须由剧情引擎判定 ### 5.5.2 幕级出演角色与背景必须由剧情引擎判定
@@ -309,7 +309,7 @@
- 角色主形象是否就绪 - 角色主形象是否就绪
- 场景幕背景是否就绪 - 场景幕背景是否就绪
这样百梦主一进入草稿精修工作区,就能直接看到: 这样陶泥儿主一进入草稿精修工作区,就能直接看到:
1. 角色已经带主形象 1. 角色已经带主形象
2. 每个场景章节的每一幕已经带背景图 2. 每个场景章节的每一幕已经带背景图
@@ -369,7 +369,7 @@ interface CustomWorldFoundationDraftSceneChapter {
1. `primaryNpcId` 必须等于 `encounterNpcIds[0]`,不允许单独填写成别的角色。 1. `primaryNpcId` 必须等于 `encounterNpcIds[0]`,不允许单独填写成别的角色。
2. 每幕必须至少有 `1` 个 NPC。 2. 每幕必须至少有 `1` 个 NPC。
3. 每幕必须有 `backgroundImageSrc``backgroundAssetId` 3. 每幕必须有 `backgroundImageSrc``backgroundAssetId`
4. `advanceRule` 由系统按幕位置默认编译,第一版不要求百梦主手改。 4. `advanceRule` 由系统按幕位置默认编译,第一版不要求陶泥儿主手改。
## 6.2 发布到运行时的蓝图结构 ## 6.2 发布到运行时的蓝图结构
@@ -416,7 +416,7 @@ sceneChapterBlueprints?: SceneChapterBlueprint[] | null;
原因: 原因:
1. 现有 `landmarks` 只足够表达地点,不足够表达幕顺序。 1. 现有 `landmarks` 只足够表达地点,不足够表达幕顺序。
2. 现有 `ChapterState` 是运行时状态,不适合直接兼做百梦主蓝图。 2. 现有 `ChapterState` 是运行时状态,不适合直接兼做陶泥儿主蓝图。
3. 独立蓝图层更适合后端编译和发布校验。 3. 独立蓝图层更适合后端编译和发布校验。
## 6.3 聊天状态扩展 ## 6.3 聊天状态扩展
@@ -483,9 +483,9 @@ type NpcChatTurnResult = {
新增规则: 新增规则:
1. 百梦主从现有“场景”列表点击任一场景卡,进入对应场景编辑弹层。 1. 陶泥儿主从现有“场景”列表点击任一场景卡,进入对应场景编辑弹层。
2. 多幕配置必须作为场景编辑弹层内的一个区块出现,归属于该场景。 2. 多幕配置必须作为场景编辑弹层内的一个区块出现,归属于该场景。
3. `scene_chapter` 仅作为保存层和运行时蓝图存在,不单独暴露在百梦主导航里。 3. `scene_chapter` 仅作为保存层和运行时蓝图存在,不单独暴露在陶泥儿主导航里。
4. 场景卡片可增加“幕数量”轻量摘要,但第一版不是阻塞项。 4. 场景卡片可增加“幕数量”轻量摘要,但第一版不是阻塞项。
## 7.2 场景编辑弹层展示要求 ## 7.2 场景编辑弹层展示要求
@@ -498,8 +498,8 @@ type NpcChatTurnResult = {
补充约束: 补充约束:
1. “场景图片”不再作为场景详情页里的独立字段展示,百梦主只能通过每一幕的“配置背景”入口管理视觉。 1. “场景图片”不再作为场景详情页里的独立字段展示,陶泥儿主只能通过每一幕的“配置背景”入口管理视觉。
2. “场景内 NPC”不再作为场景详情页里的独立字段展示百梦主只能通过每一幕角色槽位配置相遇 NPC。 2. “场景内 NPC”不再作为场景详情页里的独立字段展示陶泥儿主只能通过每一幕角色槽位配置相遇 NPC。
3. 为兼容现有运行时与旧数据结构,场景对象上的 `imageSrc / sceneNpcIds` 仍然保留,但必须由多幕配置自动回填,前台不再暴露单独编辑控件,且不能再用 `sceneNpcIds` 限制每幕可选角色。 3. 为兼容现有运行时与旧数据结构,场景对象上的 `imageSrc / sceneNpcIds` 仍然保留,但必须由多幕配置自动回填,前台不再暴露单独编辑控件,且不能再用 `sceneNpcIds` 限制每幕可选角色。
多幕区块至少展示: 多幕区块至少展示:
@@ -566,11 +566,11 @@ NPC 配置面板必须支持:
3. 不允许把不存在于当前世界角色池中的 id 写入幕配置。 3. 不允许把不存在于当前世界角色池中的 id 写入幕配置。
4. 若主角色未与当前场景或线程建立任何关联,给出发布警告。 4. 若主角色未与当前场景或线程建立任何关联,给出发布警告。
5. 存储时继续落到 `encounterNpcIds` 有序数组,槽位从左到右按顺序压缩写入。 5. 存储时继续落到 `encounterNpcIds` 有序数组,槽位从左到右按顺序压缩写入。
6. `sceneNpcIds` 不再作为百梦主字段,也不再作为幕角色选择范围;保存时只从所有幕的 `encounterNpcIds` 自动派生兼容值。 6. `sceneNpcIds` 不再作为陶泥儿主字段,也不再作为幕角色选择范围;保存时只从所有幕的 `encounterNpcIds` 自动派生兼容值。
## 7.6 幕预览 ## 7.6 幕预览
百梦主在场景编辑弹层里点击“幕预览”后,必须直接进入当前幕的运行时预览。 陶泥儿主在场景编辑弹层里点击“幕预览”后,必须直接进入当前幕的运行时预览。
要求如下: 要求如下:
@@ -633,7 +633,7 @@ interface SceneActRuntimeState {
## 8.3 幕推进规则 ## 8.3 幕推进规则
第一版不要求百梦主手填推进条件,而是由系统按幕位置默认编译: 第一版不要求陶泥儿主手填推进条件,而是由系统按幕位置默认编译:
1.`1` 幕默认 `after_primary_contact` 1.`1` 幕默认 `after_primary_contact`
- 玩家与主角色发生首次有效接触后可进入下一幕判定 - 玩家与主角色发生首次有效接触后可进入下一幕判定
@@ -871,7 +871,7 @@ Adventure 主面板在本次迭代中至少增加下面这些表现:
当下面这些结果都成立时,视为本次 PRD 已被正确落地: 当下面这些结果都成立时,视为本次 PRD 已被正确落地:
1. 百梦主可以在现有场景编辑弹层中配置每个场景的多幕。 1. 陶泥儿主可以在现有场景编辑弹层中配置每个场景的多幕。
2. 每个场景章节都可以配置 `2~5` 幕。 2. 每个场景章节都可以配置 `2~5` 幕。
3. 每一幕都可以绑定独立背景图。 3. 每一幕都可以绑定独立背景图。
4. 每一幕都可以配置有序 NPC 列表,第一位自动成为主角色。 4. 每一幕都可以配置有序 NPC 列表,第一位自动成为主角色。

View File

@@ -14,7 +14,7 @@
## 1. 一句话定义 ## 1. 一句话定义
“方洞挑战”是一个反直觉形状分拣玩法:百梦主通过 Agent 设定形状主题、洞口规则、误导节奏和反差演出,系统生成一个移动端优先的单局挑战;玩家在限时内把连续出现的形状投入正确洞口,后端根据当前关卡的真实兼容规则裁决成功、失败和连击。 “方洞挑战”是一个反直觉形状分拣玩法:陶泥儿主通过 Agent 设定形状主题、洞口规则、误导节奏和反差演出,系统生成一个移动端优先的单局挑战;玩家在限时内把连续出现的形状投入正确洞口,后端根据当前关卡的真实兼容规则裁决成功、失败和连击。
--- ---
@@ -130,7 +130,7 @@ Agent 需要把玩家一句灵感收束为上述锚点,不允许逐项盘问
落地约束: 落地约束:
1. `replyText` 是直接展示给百梦主的中文回复,不得出现 JSON、字段名、内部结构等说明。 1. `replyText` 是直接展示给陶泥儿主的中文回复,不得出现 JSON、字段名、内部结构等说明。
2. `nextConfig` 必须是完整配置,不允许只输出 patch缺失字段只能由后端用当前会话配置兜底。 2. `nextConfig` 必须是完整配置,不允许只输出 patch缺失字段只能由后端用当前会话配置兜底。
3. `shapeCount` 由后端限制在 `6``24``difficulty` 限制在 `1``10` 3. `shapeCount` 由后端限制在 `6``24``difficulty` 限制在 `1``10`
4. `quickFillRequested=true` 时,模型应直接补齐剩余配置,后端把 `progressPercent` 固定为 `100` 4. `quickFillRequested=true` 时,模型应直接补齐剩余配置,后端把 `progressPercent` 固定为 `100`

View File

@@ -14,7 +14,7 @@
## 1. 一句话定义 ## 1. 一句话定义
`survivor` 是一个 AI 原生幸存者类游戏模板:百梦主通过 Agent 设定主角幻想、敌潮母题、武器技能、成长流派和战场节奏,系统编译出一个移动端优先的俯视角割草生存作品;玩家通过移动躲避敌潮,武器自动攻击,拾取经验升级,在若干分钟内完成生存挑战、击败首领或倒下结算。 `survivor` 是一个 AI 原生幸存者类游戏模板:陶泥儿主通过 Agent 设定主角幻想、敌潮母题、武器技能、成长流派和战场节奏,系统编译出一个移动端优先的俯视角割草生存作品;玩家通过移动躲避敌潮,武器自动攻击,拾取经验升级,在若干分钟内完成生存挑战、击败首领或倒下结算。
--- ---
@@ -90,7 +90,7 @@
3. 不做复杂地形寻路、真实物理碰撞和高精度弹幕编辑器。 3. 不做复杂地形寻路、真实物理碰撞和高精度弹幕编辑器。
4. 不做多地图章节战役,只做单局挑战。 4. 不做多地图章节战役,只做单局挑战。
5. 不做局外装备养成、抽卡、永久技能树或付费强化。 5. 不做局外装备养成、抽卡、永久技能树或付费强化。
6. 不要求百梦主逐帧编辑怪物 AI、弹道曲线或数值公式。 6. 不要求陶泥儿主逐帧编辑怪物 AI、弹道曲线或数值公式。
7. 不把玩法规则说明长文默认写进 UI 面板。 7. 不把玩法规则说明长文默认写进 UI 面板。
8. 不把按钮弹出的资产、升级或参数编辑做成当前卡片下方展开内容,统一使用独立面板。 8. 不把按钮弹出的资产、升级或参数编辑做成当前卡片下方展开内容,统一使用独立面板。
9. 不让前端本地结算直接写入正式成绩、钱包、任务或排行榜。 9. 不让前端本地结算直接写入正式成绩、钱包、任务或排行榜。
@@ -161,7 +161,7 @@ Agent 必须围绕用户灵感收束这些锚点,不允许把创作入口做
落地约束: 落地约束:
1. `replyText` 是直接展示给百梦主的中文回复,不得出现 JSON、字段名或内部协议说明。 1. `replyText` 是直接展示给陶泥儿主的中文回复,不得出现 JSON、字段名或内部协议说明。
2. `progressPercent` 只能由后端校验后采纳,范围 `0~100` 2. `progressPercent` 只能由后端校验后采纳,范围 `0~100`
3. `nextDraftPatch` 只允许写入幸存者草稿字段,不允许修改平台账号、钱包或作品归属。 3. `nextDraftPatch` 只允许写入幸存者草稿字段,不允许修改平台账号、钱包或作品归属。
4. 模型不可用或结果无法解析时,接口返回明确错误,不用固定模板伪装 AI 回复。 4. 模型不可用或结果无法解析时,接口返回明确错误,不用固定模板伪装 AI 回复。

View File

@@ -4,7 +4,7 @@
## 0. 文档目的 ## 0. 文档目的
这份 PRD 用于设计 `Genarrative / 百梦` 内的 AI 文字游戏模板,暂定工程 ID 为 `text-game`,展示名可用“幕间”或“幕间文字”。它参考 MOKU / 幕间类 AI 互动平台的剧本游乐场、低门槛创作、自由行动、AI 记忆和模拟器强反馈经验,但不迁入任何外部平台工程、账号体系、社区、支付、榜单、论坛或私有存档。 这份 PRD 用于设计 `Genarrative / 陶泥儿` 内的 AI 文字游戏模板,暂定工程 ID 为 `text-game`,展示名可用“幕间”或“幕间文字”。它参考 MOKU / 幕间类 AI 互动平台的剧本游乐场、低门槛创作、自由行动、AI 记忆和模拟器强反馈经验,但不迁入任何外部平台工程、账号体系、社区、支付、榜单、论坛或私有存档。
外部参考只用于提炼产品模式: 外部参考只用于提炼产品模式:
@@ -13,13 +13,13 @@
3. TextGame.ai 体现 AI Game Master、模板即玩、自定义世界、AI 队友和持久世界状态。 3. TextGame.ai 体现 AI Game Master、模板即玩、自定义世界、AI 队友和持久世界状态。
4. Aventura 体现 lorebook、智能记忆、分支故事和本地/隐私优先的创作辅助理念。 4. Aventura 体现 lorebook、智能记忆、分支故事和本地/隐私优先的创作辅助理念。
本文只冻结百梦自己的模板落地口径。若后续实现与旧 TXT / visual novel 文档冲突,应按本文与当前后端 DDD 总纲重新修正文档后再编码。 本文只冻结陶泥儿自己的模板落地口径。若后续实现与旧 TXT / visual novel 文档冲突,应按本文与当前后端 DDD 总纲重新修正文档后再编码。
--- ---
## 1. 一句话定义 ## 1. 一句话定义
`text-game` 是一个 AI 原生文字游戏模板:百梦主可以用一句话、文档、空白或改作入口创建一个可玩的文字互动剧本,系统把题材、玩家身份、角色、地点、目标、机制、记忆和 GM 规则编译成结构化草稿;玩家进入后通过自由输入或快捷选项推动剧情,后端 AI GM 根据世界状态、长期记忆和阶段目标生成下一轮叙事、状态变化、关系变化和可继续行动。 `text-game` 是一个 AI 原生文字游戏模板:陶泥儿主可以用一句话、文档、空白或改作入口创建一个可玩的文字互动剧本,系统把题材、玩家身份、角色、地点、目标、机制、记忆和 GM 规则编译成结构化草稿;玩家进入后通过自由输入或快捷选项推动剧情,后端 AI GM 根据世界状态、长期记忆和阶段目标生成下一轮叙事、状态变化、关系变化和可继续行动。
--- ---
@@ -35,7 +35,7 @@
### 2.2 不等同于 RPG 主运行时 ### 2.2 不等同于 RPG 主运行时
RPG 主运行时承载百梦现有视觉 RPG、场景探索、战斗、NPC、物品和章节系统。 RPG 主运行时承载陶泥儿现有视觉 RPG、场景探索、战斗、NPC、物品和章节系统。
`text-game` 首版是轻量互动剧本模板不接入完整地图移动、战斗演出、装备背包、NPC 商店和 RPG 章节任务系统。它可以在以后把成熟剧本升级为 RPG 世界,但 V1 不做自动升级。 `text-game` 首版是轻量互动剧本模板不接入完整地图移动、战斗演出、装备背包、NPC 商店和 RPG 章节任务系统。它可以在以后把成熟剧本升级为 RPG 世界,但 V1 不做自动升级。
@@ -55,11 +55,11 @@ RPG 主运行时承载百梦现有视觉 RPG、场景探索、战斗、NPC、物
### 3.1 核心目标 ### 3.1 核心目标
1.百梦主在 3 分钟内从一个想法生成可试玩的文字游戏。 1.陶泥儿主在 3 分钟内从一个想法生成可试玩的文字游戏。
2. 让玩家每一轮行动都看到世界状态、关系或目标推进的反馈。 2. 让玩家每一轮行动都看到世界状态、关系或目标推进的反馈。
3. 让模板支持高复用题材:恋爱养成、古代言情、宫斗宅斗、修仙仙侠、末日生存、灵异怪谈、科幻未来、经营养成、校园都市、娱乐圈。 3. 让模板支持高复用题材:恋爱养成、古代言情、宫斗宅斗、修仙仙侠、末日生存、灵异怪谈、科幻未来、经营养成、校园都市、娱乐圈。
4. 让剧本不只是聊天对象,而是一个有目标、规则、记忆和结局的轻量模拟器。 4. 让剧本不只是聊天对象,而是一个有目标、规则、记忆和结局的轻量模拟器。
5. 让作品可以进入百梦作品架、草稿、发布、广场、存档和继续体验链路。 5. 让作品可以进入陶泥儿作品架、草稿、发布、广场、存档和继续体验链路。
### 3.2 首版不追求 ### 3.2 首版不追求
@@ -100,7 +100,7 @@ RPG 主运行时承载百梦现有视觉 RPG、场景探索、战斗、NPC、物
3. AI 可以填补空位,作为队友、对手或观众角色参与。 3. AI 可以填补空位,作为队友、对手或观众角色参与。
4. 世界状态、队伍、库存、任务进度需要持久化。 4. 世界状态、队伍、库存、任务进度需要持久化。
百梦落点: 陶泥儿落点:
1. V1 支持单人玩家 + AI 角色群。 1. V1 支持单人玩家 + AI 角色群。
2. AI 角色群只作为剧本内角色,不做多人房间。 2. AI 角色群只作为剧本内角色,不做多人房间。
@@ -115,7 +115,7 @@ RPG 主运行时承载百梦现有视觉 RPG、场景探索、战斗、NPC、物
3. 分支故事需要保存 alternate timeline 的结构,而不是只保存最终文本。 3. 分支故事需要保存 alternate timeline 的结构,而不是只保存最终文本。
4. 创作者需要能查看和修正 AI 记住了什么。 4. 创作者需要能查看和修正 AI 记住了什么。
百梦落点: 陶泥儿落点:
1. V1 只做当前主线历史与局部重生成,不做多时间线编辑器。 1. V1 只做当前主线历史与局部重生成,不做多时间线编辑器。
2. 记忆分为剧本静态设定、运行时事件摘要、角色记忆、玩家画像和未解决伏笔。 2. 记忆分为剧本静态设定、运行时事件摘要、角色记忆、玩家画像和未解决伏笔。
@@ -125,9 +125,9 @@ RPG 主运行时承载百梦现有视觉 RPG、场景探索、战斗、NPC、物
## 5. 用户角色 ## 5. 用户角色
### 5.1 百梦 ### 5.1 陶泥儿
百梦主负责创建、编辑、试玩和发布文字游戏。核心诉求是: 陶泥儿主负责创建、编辑、试玩和发布文字游戏。核心诉求是:
1. 用少量输入生成可玩的剧本。 1. 用少量输入生成可玩的剧本。
2. 控制题材、关系张力、目标、结局和禁区。 2. 控制题材、关系张力、目标、结局和禁区。
@@ -197,7 +197,7 @@ RPG 主运行时承载百梦现有视觉 RPG、场景探索、战斗、NPC、物
### 7.1 一句话创建 `idea` ### 7.1 一句话创建 `idea`
输入:百梦主写一句或几句话。 输入:陶泥儿主写一句或几句话。
示例语义: 示例语义:
@@ -1013,12 +1013,12 @@ src/components/text-game-runtime/TextGameRuntimeShell.tsx
V1 默认不新增第二套消费单位。若运行时需要扣费: V1 默认不新增第二套消费单位。若运行时需要扣费:
1. 使用平台“点”钱包。 1. 使用平台“点”钱包。
2. 扣费由 `api-server` 编排,不能在前端自行计算。 2. 扣费由 `api-server` 编排,不能在前端自行计算。
3. 幂等依赖 `clientEventId` 3. 幂等依赖 `clientEventId`
4. 测试 run 是否扣费需要产品确认。 4. 测试 run 是否扣费需要产品确认。
本文不冻结具体点数。 本文不冻结具体点数。
--- ---
@@ -1268,10 +1268,10 @@ cargo check -p api-server
1. 展示名最终用“幕间”“幕间文字”还是“AI文字游戏”。 1. 展示名最终用“幕间”“幕间文字”还是“AI文字游戏”。
2. V1 是否开放 `remix` 2. V1 是否开放 `remix`
3. V1 测试 run 是否消耗点。 3. V1 测试 run 是否消耗点。
4. V1 是否允许创作者配置封面图。 4. V1 是否允许创作者配置封面图。
5. V1 是否开放 `allowOutOfCharacterCommand` 5. V1 是否开放 `allowOutOfCharacterCommand`
6. V1 是否需要接入内容审核队列后才允许公开发布。 6. V1 是否需要接入内容审核队列后才允许公开发布。
7. 作品发现页是否单独展示文字游戏分类入口。 7. 作品发现页是否单独展示文字游戏分类入口。
无论这些默认值如何选择,三条硬边界不变:只做百梦内的 AI 文字游戏模板,复用平台接口,不迁入外部平台和 replay。 无论这些默认值如何选择,三条硬边界不变:只做陶泥儿内的 AI 文字游戏模板,复用平台接口,不迁入外部平台和 replay。

View File

@@ -683,7 +683,7 @@ GET /api/runtime/profile/save-archives
1. 创作底稿生成和运行时 GM 输出由 `api-server` 编排 `platform-llm`SpacetimeDB reducer 不直接调用 LLM。 1. 创作底稿生成和运行时 GM 输出由 `api-server` 编排 `platform-llm`SpacetimeDB reducer 不直接调用 LLM。
2. 图片和音乐生成 / 上传由 `api-server` 编排平台资产服务,不把二进制写入 SpacetimeDB。 2. 图片和音乐生成 / 上传由 `api-server` 编排平台资产服务,不把二进制写入 SpacetimeDB。
3. 消耗点时走平台钱包流水;不得迁入外部仓库积分表。 3. 消耗点时走平台钱包流水;不得迁入外部仓库积分表。
4. prompt 必须输出可解析 JSON step 或工具调用结果;解析失败时由后端 repair不让前端猜测业务状态。 4. prompt 必须输出可解析 JSON step 或工具调用结果;解析失败时由后端 repair不让前端猜测业务状态。
--- ---
@@ -1801,7 +1801,7 @@ cargo check -p api-server
这些问题不阻塞本文冻结边界,但进入编码前需要产品确认默认值: 这些问题不阻塞本文冻结边界,但进入编码前需要产品确认默认值:
1. 视觉小说运行时 AI 推进是否首版收费,以及单次推进默认点数。 1. 视觉小说运行时 AI 推进是否首版收费,以及单次推进默认点数。
2. 文档上传首版支持的最大大小和格式。 2. 文档上传首版支持的最大大小和格式。
3. 角色立绘、场景图是否首版自动生成,还是仅提供手动上传和后续生成按钮。 3. 角色立绘、场景图是否首版自动生成,还是仅提供手动上传和后续生成按钮。
4. 属性面板是否首版关闭,还是只对内部白名单开启。 4. 属性面板是否首版关闭,还是只对内部白名单开启。

View File

@@ -0,0 +1,101 @@
# 宝贝爱画寓教于乐独立关卡 PRD 2026-05-13
## 1. 目标
新增寓教于乐内容线独立关卡:
```text
宝贝爱画
```
工程 ID 固定为:
```text
baby-love-drawing
```
该关卡默认出现在“发现 / 寓教于乐”板块下方。当前阶段只做本地 Demo 保存,验证完成后再补正式持久化。
## 2. 关卡结构
启动宝贝爱画后进入绘画运行态:
1. 屏幕中央是带边框的空白画板;
2. 画板边框内是可绘画区域;
3. 画板外左侧展示彩虹 7 色;
4. 画板外右侧中下方展示画笔和橡皮;
5. 用户进入内容后默认手持画笔;
6. 手持画笔或橡皮时,屏幕上实时显示跟随右手位置的工具图案标识。
## 3. 输入规则
颜色选择:
1. 仅检测左手;
2. 左手悬停在某个颜色区域 1.5 秒后,选中该颜色;
3. 颜色固定为彩虹 7 色。
工具切换:
1. 右手移动到画笔或橡皮工具区域;
2. 右手握拳后,将手里的工具切换为对应工具。
绘画与擦除:
1. 右手在画布区域握拳时,当前工具生效;
2. 当前工具为画笔时留下轨迹;
3. 当前工具为橡皮时擦除轨迹;
4. 右手张开时,画笔或橡皮抬起,不在画布上生效。
按钮选择:
1. 完成;
2. 使用绘画魔法;
3. 保存;
4. 再画一张;
5. 返回。
以上按钮都使用任一手悬停 2 秒完成选中。
## 4. 绘画魔法
用户完成绘画后,可使用“绘画魔法”。
绘画魔法使用 image-2以用户绘画内容和笔触轨迹生成对应绘本风格图片内容。
前端不得直接读取、拼接或暴露图片生成密钥。image-2 调用必须通过后端代理。
## 5. 保存规则
当前只做本地 Demo 保存。
保存规则:
1. 魔法生成前保存,只保存一张原图;
2. 若用户未保存原图,直接点击魔法生成,则魔法生成后保存时同时保存原图和魔法图;
3. 保存完毕后,可继续“再画一张”或“返回”。
## 6. 展示与开关
宝贝爱画只属于寓教于乐内容线。
`VITE_ENABLE_EDUTAINMENT_ENTRY` 关闭时:
1. 不展示“发现 / 寓教于乐”频道;
2. 不展示宝贝爱画默认卡片;
3. 不允许通过 `/runtime/baby-love-drawing` 直达运行态。
## 7. 验收
1. 寓教于乐开启时,“发现 / 寓教于乐”下方展示“宝贝爱画”默认关卡卡片;
2. 寓教于乐关闭时,不展示宝贝爱画,也不能直达运行态;
3. 进入后展示空白画板、彩虹 7 色、画笔和橡皮;
4. 默认工具为画笔;
5. 左手悬停颜色 1.5 秒后选中颜色;
6. 右手移动到工具区并握拳后切换画笔或橡皮;
7. 右手握拳在画布内绘制或擦除,张开时不生效;
8. 任一手悬停按钮 2 秒后触发按钮;
9. 完成后可保存原图;
10. 完成后可使用绘画魔法生成绘本风格图片;
11. 未保存原图直接使用绘画魔法后,保存会同时保存原图和魔法图;
12. 保存后可再画一张或返回。

View File

@@ -0,0 +1,117 @@
# 宝贝识物寓教于乐模板 PRD 2026-05-11
## 1. 目标
新增寓教于乐内容线的创作模板:
```text
宝贝识物
```
创作者必须通过该模板创作并发布作品后,用户才能在寓教于乐板块体验对应关卡。
本模板只服务儿童动作 Demo 内容线,不把普通教育题材作品自动归入寓教于乐。
## 2. 创作输入
创作者必须填写两个物品名称:
1. 物品 A 名称;
2. 物品 B 名称。
两个名称都必须去除首尾空白后非空。当前阶段不新增题材、难度、计时、失败次数、分数、体力或递增规则。
## 3. 生成规则
提交后生成一份宝贝识物草稿,草稿包含:
1. 模板 ID`baby-object-match`
2. 模板名称:`宝贝识物`
3. 两个物品;
4. 两个物品图;
5. 游戏视觉主题包;
6. 作品标签。
物品图使用 VectorEngine `gpt-image-2-all` / image-2 生成。图片生成只能走后端接口,前端不得读取、拼接或暴露 `VECTOR_ENGINE_API_KEY`
每个关键词只生成一张围绕该关键词的单一物品形象。生成 prompt 必须锁定寓教于乐板块统一的卡通绘本草地舞台插画风,但最终画面不生成背景、场景、氛围渲染、人物、手、篮子、礼物盒、文字、水印或 UI。服务端必须把生成结果转成透明 PNG并执行透明抠图后处理只有透明抠图后的素材才允许写入草稿 `itemAssets` 并进入游戏运行态。
同一次创作还必须使用 image-2 生成游戏视觉主题包包含背景环境、UI 装饰框、礼物盒、篮子和烟雾弹出特效资源。主题包必须继续保持寓教于乐插画风,并根据用户填写的两个物品关键词匹配主题:例如关键词偏动漫角色或玩具时,背景环境和元素可使用动漫、玩具主题;关键词偏水果时,背景环境和元素可匹配果园、自然主题;其它关键词按其语义匹配合适主题。主题包不得改变关卡玩法规则,不新增文字说明、额外按钮或额外判定规则。
视觉主题包的资源边界:
1. 背景环境图不做透明抠图,但必须保证屏幕中间、中下方和底部左右篮子区域清爽,不遮挡放大后的物品、礼物盒和篮子;
2. UI 装饰框用于字幕条和计数器风格化包装,只生成装饰边框和主题点缀,不生成文字、数字或按钮;
3. 礼物盒资源输出为透明 PNG运行态按当前礼盒视觉的 2 倍尺寸展示,素材主体必须饱满清晰;
4. 篮子资源输出为透明 PNG运行态按当前篮子视觉的 1.5 倍尺寸展示,左右篮子仍固定为两个物品对应选项,篮子造型资源可以复用同一张主题篮子图;
5. 烟雾弹出特效资源输出为透明 PNG用于礼物盒打开瞬间覆盖开盒区域并承接中央物品弹出不生成物品、篮子、礼物盒或文字。
当前本地 Demo 阶段已接入真实 image-2 资源链路。创作提交必须成功获得 `generationProvider = "vector-engine-gpt-image-2"` 的两个物品透明 PNG 和完整视觉主题包后才能进入结果页、试玩或发布若后端接口、登录态、VectorEngine 配置或上游生成失败,前端必须停留在生成失败状态并展示错误,不得静默回退为占位图。历史草稿中若仍存在 `generationProvider = "placeholder"` 的占位资源,结果页必须提示重新生成,试玩和发布前必须先补齐 image-2 资源。
## 4. 标签规则
发布作品必须携带精确标签:
```text
寓教于乐
```
标签识别只接受精确等于 `寓教于乐`。不接受 `儿童教育``动作教育``寓教于乐 ` 等近似标签。
宝贝识物草稿与发布 payload 中都必须保留该标签。发布后的公开展示、搜索、深链和入口开关继续遵循 `CHILD_MOTION_EDUTAINMENT_DISCOVER_ENTRY_2026-05-09.md`
## 5. 结果页能力
结果页展示:
1. 作品名称;
2. 两个物品名称;
3. 两个物品图;
4. 标签;
5. 保存草稿;
6. 发布;
7. 试玩。
结果页不展示长规则说明文案。试玩按钮直接进入宝贝识物首关本地运行态。
试玩按钮进入宝贝识物首关运行态,运行态消费当前草稿中的两个物品名称和两张物品图,不重新生成或改写物品内容。
若草稿包含视觉主题包运行态还必须消费该主题包中的背景环境、UI 装饰、礼物盒、篮子和烟雾弹出特效资源;旧草稿或接口失败时允许回退到当前 CSS 绘本风兜底。
## 6. 发布后体验
发布完成后作品应进入寓教于乐内容线,并在寓教于乐入口开启时可被板块消费。
入口关闭时,发布作品完全不可见,不能通过推荐、发现普通频道、搜索、作品号、公开详情深链或浏览历史访问。
## 7. 与运行时线程的边界
本 PRD 同步约束首关运行态,已确认规则包括:
1. 进入关卡后礼物盒自动打开并弹出首个随机物品;
2. 每轮仅中间礼物盒跳出的物品随机;左右两侧篮子固定为当前草稿两个物品的顺序;
3. 下一关按钮当前占位;
4. 不新增用户未确认的计时、失败次数、分数、体力或难度递增。
5. 屏幕中上方字幕固定为“将物品放入对应的篮子里”。
6. 礼物盒位于屏幕中下方并按当前视觉放大一倍,首次进入关卡和每次正确反馈结束后的新轮次都从上方落下后自动打开。
7. 屏幕下方左侧和右侧分别展示两个固定篮子,左侧固定使用草稿第一个物品图,右侧固定使用草稿第二个物品图。
8. 左右篮子按当前视觉放大 50%。
9. 礼物盒打开时播放烟雾特效,中央物品从烟雾特效中弹出;物品弹出后礼物盒从舞台移除。
10. 明确左手连续横向移动达到阈值时将当前物品送入左侧篮子,明确右手连续横向移动达到阈值时将当前物品送入右侧篮子;选篮不使用动作名判定,侧别未知的手部轨迹不参与选篮。
11. 正确时展示“真棒”字幕和正确特效;错误时展示“再想一想吧”字幕和错误特效,物品回到中央。
12. 成功 20 次后展示“恭喜你!小朋友!”字幕和特效,并展示“再来一次”和“下一关”按钮。
13. 当前本地 Demo 阶段音效与语音播报接口只预留调用点,不在前端写死外部硬件或服务接口。
## 8. 验收
1. 创作入口显示 `宝贝识物` 并可进入模板表单。
2. 未填写任一物品名称时不能生成草稿。
3. 生成草稿后进入结果页,展示两个物品名称和物品图。
4. 生成草稿后包含视觉主题包主题包含背景环境、UI 装饰框、礼物盒、篮子和烟雾弹出特效资源。
5. 草稿标签中始终包含精确 `寓教于乐`
6. 发布 payload 始终包含精确 `寓教于乐`
7. 发布完成后出现分享弹窗或发布完成状态。
8. 前端不读取或暴露 VectorEngine 密钥。
9. 结果页试玩进入宝贝识物运行态,不再显示“试玩关卡正在接入中”。
10. 运行态通过鼠标左键拖动映射左手横向移动,通过鼠标右键拖动映射右手横向移动。
11. 成功 20 次后出现“再来一次”和“下一关”按钮。

View File

@@ -12,7 +12,7 @@ Phase 1 的目标不是重做现有拼图创作系统,也不是把 Agent 降
## 1. 一句话定义 ## 1. 一句话定义
Phase 1 是一个“只开放拼图模板的创意互动内容生成 Agent”它必须先展示多个拼图模板候选用户选择某个模板后再确认该模板下的关卡模式、关卡数和预计点范围;确认后才通过拼图模块 Tool 填充同一份 `PuzzleResultDraft` 草稿字段,并复用现有 `puzzle-result``puzzle-runtime` 完成表单编辑、自然语言修订和立即试玩闭环。 Phase 1 是一个“只开放拼图模板的创意互动内容生成 Agent”它必须先展示多个拼图模板候选用户选择某个模板后再确认该模板下的关卡模式、关卡数和预计点范围;确认后才通过拼图模块 Tool 填充同一份 `PuzzleResultDraft` 草稿字段,并复用现有 `puzzle-result``puzzle-runtime` 完成表单编辑、自然语言修订和立即试玩闭环。
--- ---
@@ -91,7 +91,7 @@ APIMart Responses 请求必须按多模态内容块组织:
1. 新增 `platform-agent` PoC crate封装 LangChain-Rust 的 Function Calling / AgentExecutor 能力。 1. 新增 `platform-agent` PoC crate封装 LangChain-Rust 的 Function Calling / AgentExecutor 能力。
2. 新增创意 Agent shared contract支持阶段、消息、模板选择、积分范围、关卡图片计划、目标拼图 session 绑定。 2. 新增创意 Agent shared contract支持阶段、消息、模板选择、积分范围、关卡图片计划、目标拼图 session 绑定。
3. 新增拼图模板协议,当前只提供一个可用拼图模板,但仍必须显式展示选择步骤。 3. 新增拼图模板协议,当前只提供一个可用拼图模板,但仍必须显式展示选择步骤。
4. 拼图模板卡必须展示模板标题、预览、选择理由、单关卡/多关卡能力、计划关卡数、预计点范围。 4. 拼图模板卡必须展示模板标题、预览、选择理由、单关卡/多关卡能力、计划关卡数、预计点范围。
5. 用户确认模板后Agent 才能创建或复用拼图 session并填充 `PuzzleResultDraft` 5. 用户确认模板后Agent 才能创建或复用拼图 session并填充 `PuzzleResultDraft`
6. Agent 可写草稿字段只允许: 6. Agent 可写草稿字段只允许:
- `PuzzleResultDraft.workTitle` - `PuzzleResultDraft.workTitle`
@@ -133,7 +133,7 @@ APIMart Responses 请求必须按多模态内容块组织:
-> Agent 思考并选择拼图模板 -> Agent 思考并选择拼图模板
-> 前端展示多个拼图模板卡 -> 前端展示多个拼图模板卡
-> 用户选择一个模板 -> 用户选择一个模板
-> 前端弹出该模板的关卡模式、关卡数和预计点范围确认面板 -> 前端弹出该模板的关卡模式、关卡数和预计点范围确认面板
-> Agent 调用拼图模块 Tool 生成草稿字段和图片计划 -> Agent 调用拼图模块 Tool 生成草稿字段和图片计划
-> 拼图模块创建 / 更新 puzzle_agent_session -> 拼图模块创建 / 更新 puzzle_agent_session
-> 拼图模块生成单关卡或多关卡图片候选 -> 拼图模块生成单关卡或多关卡图片候选
@@ -174,7 +174,7 @@ Agent 生成草稿前必须展示独立确认卡。确认卡字段:
| 选择理由 | `reason` | 一到两句中文,不展示内部推理链。 | | 选择理由 | `reason` | 一到两句中文,不展示内部推理链。 |
| 关卡模式 | `selectedLevelMode` | 单关卡 / 多关卡。 | | 关卡模式 | `selectedLevelMode` | 单关卡 / 多关卡。 |
| 计划关卡数 | `plannedLevelCount` | 在模板 min/max 内。 | | 计划关卡数 | `plannedLevelCount` | 在模板 min/max 内。 |
| 预计点 | `costRange` | 显示 `minPoints``maxPoints` 点。 | | 预计点 | `costRange` | 显示 `minPoints``maxPoints` 点。 |
交互: 交互:
@@ -529,7 +529,7 @@ done
事件要求: 事件要求:
1. `messages/stream` 首轮必须先返回 `puzzle_template_catalog`,并把 `puzzleTemplateCatalog` 写入 session`puzzleTemplateSelection` 保持为空。 1. `messages/stream` 首轮必须先返回 `puzzle_template_catalog`,并把 `puzzleTemplateCatalog` 写入 session`puzzleTemplateSelection` 保持为空。
2. 用户点击某个模板后,前端基于模板协议打开独立配置确认面板,确认关卡模式、关卡数和预计点范围。 2. 用户点击某个模板后,前端基于模板协议打开独立配置确认面板,确认关卡模式、关卡数和预计点范围。
3. `confirm-template` 后才允许写入 `puzzle_template_selection``puzzle_level_plan` 并创建拼图草稿。 3. `confirm-template` 后才允许写入 `puzzle_template_selection``puzzle_level_plan` 并创建拼图草稿。
4. `target_session` 必须带 `targetSessionId` 和可跳转 stage。 4. `target_session` 必须带 `targetSessionId` 和可跳转 stage。
5. 流式失败时保留已显示文字,并发送结构化 `error` 5. 流式失败时保留已显示文字,并发送结构化 `error`
@@ -719,7 +719,7 @@ Agent 必须被提示为:
1. 你是创意互动内容生成 Agent不是规则分类器。 1. 你是创意互动内容生成 Agent不是规则分类器。
2. 当前产品只开放拼图模板。 2. 当前产品只开放拼图模板。
3. 你要相信自己的图文理解能力,主动形成拼图创意。 3. 你要相信自己的图文理解能力,主动形成拼图创意。
4. 即使只有拼图可用,也必须显式选择模板并展示预计点范围。 4. 即使只有拼图可用,也必须显式选择模板并展示预计点范围。
5. 未经用户确认模板,不得创建草稿。 5. 未经用户确认模板,不得创建草稿。
6. 你只能调用已注册工具。 6. 你只能调用已注册工具。
7. 可写草稿字段只限 `workTitle``workDescription``workTags``levels[].levelName``levels[].pictureDescription``levels[].pictureReference` 7. 可写草稿字段只限 `workTitle``workDescription``workTags``levels[].levelName``levels[].pictureDescription``levels[].pictureReference`
@@ -996,7 +996,7 @@ npm run test -- PuzzleResultView
4. `PuzzleResultView` 已显示并编辑 `levels[].pictureReference`,并在智能创作链路进入结果页时显示自然语言修订输入条,调用 `streamCreativeDraftEdit` 后回写同一份拼图 session。 4. `PuzzleResultView` 已显示并编辑 `levels[].pictureReference`,并在智能创作链路进入结果页时显示自然语言修订输入条,调用 `streamCreativeDraftEdit` 后回写同一份拼图 session。
5. 前端定向验证已通过:`npm run typecheck``npm run check:encoding``npx eslint src/services/creative-agent/creativeAgentClient.ts src/services/creative-agent/creativeAgentSse.ts src/services/creative-agent/index.ts src/components/creative-agent/CreativeAgentWorkspace.tsx src/components/creative-agent/CreativeAgentInputComposer.tsx src/components/creative-agent/CreativeAgentTemplateConfirmPanel.tsx src/components/creative-agent/CreativeAgentStageTimeline.tsx src/components/creative-agent/creativeAgentViewModel.ts src/components/platform-entry/PlatformEntryFlowShellImpl.tsx src/components/platform-entry/platformEntryCreationTypes.ts src/components/platform-entry/PlatformEntryCreationTypeModal.tsx src/components/puzzle-result/PuzzleResultView.tsx --max-warnings 0``npm run test -- src/services/creative-agent/creativeAgentSse.test.ts``npm run test -- src/components/puzzle-result/PuzzleResultView.test.tsx``npm run test -- src/components/platform-entry/platformEntryCreationTypes.test.ts src/components/custom-world-home/CustomWorldCreationHub.interaction.test.tsx``npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "create hub hides RPG"` 5. 前端定向验证已通过:`npm run typecheck``npm run check:encoding``npx eslint src/services/creative-agent/creativeAgentClient.ts src/services/creative-agent/creativeAgentSse.ts src/services/creative-agent/index.ts src/components/creative-agent/CreativeAgentWorkspace.tsx src/components/creative-agent/CreativeAgentInputComposer.tsx src/components/creative-agent/CreativeAgentTemplateConfirmPanel.tsx src/components/creative-agent/CreativeAgentStageTimeline.tsx src/components/creative-agent/creativeAgentViewModel.ts src/components/platform-entry/PlatformEntryFlowShellImpl.tsx src/components/platform-entry/platformEntryCreationTypes.ts src/components/platform-entry/PlatformEntryCreationTypeModal.tsx src/components/puzzle-result/PuzzleResultView.tsx --max-warnings 0``npm run test -- src/services/creative-agent/creativeAgentSse.test.ts``npm run test -- src/components/puzzle-result/PuzzleResultView.test.tsx``npm run test -- src/components/platform-entry/platformEntryCreationTypes.test.ts src/components/custom-world-home/CustomWorldCreationHub.interaction.test.tsx``npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "create hub hides RPG"`
6. 2026-05-05 补充:智能创作工作区的过程区不再只展示最近 6 个短进度标签,改为基于 SSE 事件生成详细过程项,覆盖阶段切换、工具开始/完成、模板选择、预计点、关卡计划、反思、目标绑定、错误和完成事件;刷新或非流式恢复时会从 session 快照补模板、关卡计划和目标绑定,移动端使用紧凑可滚动列表。 6. 2026-05-05 补充:智能创作工作区的过程区不再只展示最近 6 个短进度标签,改为基于 SSE 事件生成详细过程项,覆盖阶段切换、工具开始/完成、模板选择、预计点、关卡计划、反思、目标绑定、错误和完成事件;刷新或非流式恢复时会从 session 快照补模板、关卡计划和目标绑定,移动端使用紧凑可滚动列表。
7. 2026-05-05 补充:流式过程新增 `thought_summary_delta` 事件,只展示可给用户看的“思考摘要”,例如素材理解、模板选择摘要和关卡规划摘要;该事件不承载模型内部推理链,前端按 `thoughtId` 合并多段 delta 后在过程面板中显示为一条持续更新的“思考摘要”。 7. 2026-05-05 补充:流式过程新增 `thought_summary_delta` 事件,只展示可给用户看的“思考摘要”,例如素材理解、模板选择摘要和关卡规划摘要;该事件不承载模型内部推理链,前端按 `thoughtId` 合并多段 delta 后在过程面板中显示为一条持续更新的“思考摘要”。
8. 2026-05-06 补充:智能创作 Agent 的模板步骤拆成两段,`messages/stream` 只返回 `puzzle_template_catalog` 和 session 里的 `puzzleTemplateCatalog`;前端先展示多个模板卡,用户选中后才打开独立确认面板并提交 `confirm-template``puzzle_template_selection``puzzle_cost_range``puzzle_level_plan` 不再由首轮消息流自动发送。工作区在 `sessionId` 变化时必须清空本地待确认模板,避免上一会话已点开的确认面板残留到新会话。 8. 2026-05-06 补充:智能创作 Agent 的模板步骤拆成两段,`messages/stream` 只返回 `puzzle_template_catalog` 和 session 里的 `puzzleTemplateCatalog`;前端先展示多个模板卡,用户选中后才打开独立确认面板并提交 `confirm-template``puzzle_template_selection``puzzle_cost_range``puzzle_level_plan` 不再由首轮消息流自动发送。工作区在 `sessionId` 变化时必须清空本地待确认模板,避免上一会话已点开的确认面板残留到新会话。
@@ -1051,7 +1051,7 @@ cargo check -p api-server
1. 任务 G 已补 API facade 回归:`cargo test -p api-server creative_agent` 覆盖未确认模板时 `draft-edits/stream` 返回错误且不绑定 `targetBinding`,以及 `rpg.unsupported` 非拼图模板确认被拒绝且不创建目标 session。 1. 任务 G 已补 API facade 回归:`cargo test -p api-server creative_agent` 覆盖未确认模板时 `draft-edits/stream` 返回错误且不绑定 `targetBinding`,以及 `rpg.unsupported` 非拼图模板确认被拒绝且不创建目标 session。
2. 任务 G 已补拼图模块回归:`cargo test -p module-puzzle creative` 同时覆盖单关卡、多关卡 draft 和 `pictureReference` / `workDescription -> summary` / `workTags -> themeTags` 的 Phase 1 映射。 2. 任务 G 已补拼图模块回归:`cargo test -p module-puzzle creative` 同时覆盖单关卡、多关卡 draft 和 `pictureReference` / `workDescription -> summary` / `workTags -> themeTags` 的 Phase 1 映射。
3. 任务 G 已补前端回归:`CreativeAgentTemplateConfirmPanel.test.tsx` 覆盖模板确认卡点范围,`CreativeAgentWorkspace.test.tsx` 覆盖 target ready 后展示打开草稿入口,并通过 `resolveCreativeAgentTargetSelectionStage` 固定 `puzzle-result` 跳转落点;`creativeAgentSse.test.ts` 覆盖 creative Agent SSE 事件与 draft edit payload。 3. 任务 G 已补前端回归:`CreativeAgentTemplateConfirmPanel.test.tsx` 覆盖模板确认卡点范围,`CreativeAgentWorkspace.test.tsx` 覆盖 target ready 后展示打开草稿入口,并通过 `resolveCreativeAgentTargetSelectionStage` 固定 `puzzle-result` 跳转落点;`creativeAgentSse.test.ts` 覆盖 creative Agent SSE 事件与 draft edit payload。
4. 定向验收已通过:`npm run check:encoding``npm run test -- src/components/creative-agent/CreativeAgentWorkspace.test.tsx src/components/creative-agent/CreativeAgentTemplateConfirmPanel.test.tsx src/services/creative-agent/creativeAgentSse.test.ts``npm run test -- src/components/puzzle-result/PuzzleResultView.test.tsx``cargo test -p module-puzzle creative``cargo test -p module-puzzle puzzle_draft``cargo test -p shared-contracts creative_agent``cargo test -p api-server creative_agent``cargo check -p api-server` 4. 定向验收已通过:`npm run check:encoding``npm run test -- src/components/creative-agent/CreativeAgentWorkspace.test.tsx src/components/creative-agent/CreativeAgentTemplateConfirmPanel.test.tsx src/services/creative-agent/creativeAgentSse.test.ts``npm run test -- src/components/puzzle-result/PuzzleResultView.test.tsx``cargo test -p module-puzzle creative``cargo test -p module-puzzle puzzle_draft``cargo test -p shared-contracts creative_agent``cargo test -p api-server creative_agent``cargo check -p api-server`
5. 全量 `npm run typecheck` 当前被视觉小说链路既有类型错误阻塞,包含 `packages/shared/src/contracts/visualNovel.ts``src/components/platform-entry/PlatformEntryFlowShellImpl.tsx``onSelectVisualNovel` 缺失和 `src/components/visual-novel-result/VisualNovelResultView.tsx`;全量 `npm run test` 当前被既有 RPG 首页搜索 / 拼图 workspace 旧断言等非本任务用例阻塞。上述阻塞不来自本次 creative-agent Task G 回归补测。 5. 全量 `npm run typecheck` 当前被视觉小说链路既有类型错误阻塞,包含 `packages/shared/src/contracts/visualNovel.ts``src/components/platform-entry/PlatformEntryFlowShellImpl.tsx``onSelectVisualNovel` 缺失和 `src/components/visual-novel-result/VisualNovelResultView.tsx`;全量 `npm run test` 当前被既有 RPG 首页搜索 / 拼图 workspace 旧断言等非本任务用例阻塞。上述阻塞不来自本次 creative-agent Task G 回归补测。
@@ -1095,7 +1095,7 @@ cargo check -p api-server
1. 用户从创作中心进入创意 Agent。 1. 用户从创作中心进入创意 Agent。
2. 用户输入文字和 1 张图片后SSE 显示感知和思考阶段。 2. 用户输入文字和 1 张图片后SSE 显示感知和思考阶段。
3. Agent 显式展示拼图模板确认卡。 3. Agent 显式展示拼图模板确认卡。
4. 确认卡显示预计点范围。 4. 确认卡显示预计点范围。
5. 未确认模板时不会创建拼图草稿。 5. 未确认模板时不会创建拼图草稿。
6. 确认模板后进入草稿生成。 6. 确认模板后进入草稿生成。
7. 生成的草稿字段对齐 `workTitle``workDescription``workTags``levels[].levelName``levels[].pictureDescription``levels[].pictureReference` 7. 生成的草稿字段对齐 `workTitle``workDescription``workTags``levels[].levelName``levels[].pictureDescription``levels[].pictureReference`

View File

@@ -4,7 +4,7 @@
## 0. 目标 ## 0. 目标
把“点 / 游戏时长 / 玩过”这一排信息卡,从静态数字展示升级成稳定的个人数据看板,让玩家在进入“我的”页时一眼知道自己的账号资产和游玩投入。 把“点 / 游戏时长 / 玩过”这一排信息卡,从静态数字展示升级成稳定的个人数据看板,让玩家在进入“我的”页时一眼知道自己的账号资产和游玩投入。
--- ---
@@ -12,7 +12,7 @@
当前三个数字来源并不统一: 当前三个数字来源并不统一:
1. 点来自当前存档上下文,不等于账号总资产 1. 点来自当前存档上下文,不等于账号总资产
2. 游戏时长依赖当前快照,不代表全账号累计 2. 游戏时长依赖当前快照,不代表全账号累计
3. 玩过当前几乎是硬编码推导,不是真实统计 3. 玩过当前几乎是硬编码推导,不是真实统计
@@ -39,11 +39,11 @@
## 3. 指标定义 ## 3. 指标定义
## 3.1 ## 3.1
定义: 定义:
- 当前账号可立即消费的点余额 - 当前账号可立即消费的点余额
不使用: 不使用:
@@ -80,7 +80,7 @@
点击行为: 点击行为:
1. 点卡 1. 点卡
- 打开资产流水抽屉 - 打开资产流水抽屉
2. 游戏时长卡 2. 游戏时长卡
- 打开游玩统计抽屉 - 打开游玩统计抽屉
@@ -125,7 +125,7 @@
返回: 返回:
- 点流水列表 - 点流水列表
### `GET /api/profile/play-stats` ### `GET /api/profile/play-stats`

View File

@@ -73,7 +73,7 @@
首期奖励建议采用可控方案: 首期奖励建议采用可控方案:
1. 邀请人获得 1. 邀请人获得
2. 被邀请人获得新手奖励 2. 被邀请人获得新手奖励
所有奖励必须走台账,不允许前端本地加值。 所有奖励必须走台账,不允许前端本地加值。
@@ -164,4 +164,4 @@
1. 用户能看到自己的邀请码与邀请链接 1. 用户能看到自己的邀请码与邀请链接
2. 可以一键复制或分享 2. 可以一键复制或分享
3. 邀请成功后能看到正确统计 3. 邀请成功后能看到正确统计
4. 奖励到账后点余额同步变化 4. 奖励到账后点余额同步变化

View File

@@ -51,11 +51,11 @@
首期只保留两种状态: 首期只保留两种状态:
1. `普通用户` 1. `普通用户`
2. `百梦会员` 2. `陶泥儿会员`
会员权益首期建议控制在直接可编码的范围: 会员权益首期建议控制在直接可编码的范围:
1. 每日额外点领取额度 1. 每日额外点领取额度
2. 高级世界模板或创作槽位 2. 高级世界模板或创作槽位
3. 更高的云存档上限 3. 更高的云存档上限
4. 会员专属标识 4. 会员专属标识
@@ -119,7 +119,7 @@
支付成功后: 支付成功后:
1. 刷新会员状态 1. 刷新会员状态
2. 刷新点余额 2. 刷新点余额
3. 刷新权益标签 3. 刷新权益标签
--- ---

View File

@@ -8,7 +8,7 @@
1. 头像编辑 1. 头像编辑
2. 昵称编辑 2. 昵称编辑
3. 百梦号展示与复制 3. 陶泥号展示与复制
4. 登录方式与绑定状态展示 4. 登录方式与绑定状态展示
5. 进入资料编辑抽屉 5. 进入资料编辑抽屉
@@ -22,7 +22,7 @@
- 头像占位 - 头像占位
- 昵称 - 昵称
- 百梦 - 陶泥
- 登录方式 - 登录方式
- 绑定状态 - 绑定状态
@@ -31,7 +31,7 @@
1. 头像按钮和昵称编辑按钮都直接打开账号弹窗,信息架构混在一起 1. 头像按钮和昵称编辑按钮都直接打开账号弹窗,信息架构混在一起
2. 头像当前只是视觉壳,没有真正的上传与裁剪能力 2. 头像当前只是视觉壳,没有真正的上传与裁剪能力
3. 昵称缺少明确的编辑规则与唯一性策略 3. 昵称缺少明确的编辑规则与唯一性策略
4. 百梦号只是前端拼接值,不适合长期作为正式公开识别码 4. 陶泥号只是前端拼接值,不适合长期作为正式公开识别码
--- ---
@@ -43,7 +43,7 @@
2. 资料编辑抽屉 2. 资料编辑抽屉
3. 头像上传、裁切、保存 3. 头像上传、裁切、保存
4. 昵称编辑、校验、保存 4. 昵称编辑、校验、保存
5. 百梦号固定生成与复制 5. 陶泥号固定生成与复制
6. 登录方式与账号状态标签展示 6. 登录方式与账号状态标签展示
## 2.2 本期不做 ## 2.2 本期不做
@@ -63,7 +63,7 @@
- 用户头像 - 用户头像
- 用户昵称 - 用户昵称
- `百梦号` - `陶泥号`
- 登录方式标签 - 登录方式标签
- 账号状态标签 - 账号状态标签
- 资料编辑入口 - 资料编辑入口
@@ -85,7 +85,7 @@
- 打开“编辑资料”抽屉,并默认聚焦头像编辑区域 - 打开“编辑资料”抽屉,并默认聚焦头像编辑区域
2. 点击昵称右侧编辑按钮 2. 点击昵称右侧编辑按钮
- 打开“编辑资料”抽屉,并默认聚焦昵称输入框 - 打开“编辑资料”抽屉,并默认聚焦昵称输入框
3. 点击百梦号复制按钮 3. 点击陶泥号复制按钮
- 直接复制,并给出轻提示 - 直接复制,并给出轻提示
4. 点击登录方式/状态标签 4. 点击登录方式/状态标签
- 不跳页,不弹复杂说明 - 不跳页,不弹复杂说明
@@ -103,6 +103,7 @@
3. 上传后进入正方形裁切 3. 上传后进入正方形裁切
4. 服务端生成 `256x256` 主图和 `96x96` 缩略图 4. 服务端生成 `256x256` 主图和 `96x96` 缩略图
5. 超过大小或格式限制时直接拦截 5. 超过大小或格式限制时直接拦截
6. 头像裁切工具必须复用平台通用正方形图片裁剪弹窗,并与拼图图片上传裁剪保持同一套拖拽裁剪框、八向边界手柄、九宫格辅助线、遮罩和移动端触控行为;不得在头像侧保留独立的缩放/横向/纵向滑杆实现
支持格式: 支持格式:
@@ -125,9 +126,9 @@
4. 不要求全站唯一,但要允许后端做敏感词审核 4. 不要求全站唯一,但要允许后端做敏感词审核
5. 审核失败时返回明确错误 5. 审核失败时返回明确错误
## 4.3 百梦 ## 4.3 陶泥
百梦号规则: 陶泥号规则:
1. 作为公开可复制识别码 1. 作为公开可复制识别码
2. 用户创建后固定生成,不允许用户修改 2. 用户创建后固定生成,不允许用户修改
@@ -207,6 +208,6 @@
1. 用户可以上传并保存头像 1. 用户可以上传并保存头像
2. 用户可以修改昵称并实时看到更新 2. 用户可以修改昵称并实时看到更新
3. 百梦号由后端返回,复制后可正常使用 3. 陶泥号由后端返回,复制后可正常使用
4. 未登录或待绑定状态下,不出现无效编辑入口 4. 未登录或待绑定状态下,不出现无效编辑入口
5. 页面不出现冗长规则说明文案 5. 页面不出现冗长规则说明文案

View File

@@ -0,0 +1,90 @@
# “我的”页签法律信息与登录协议确认 PRD
## 1. 目标
在平台“我的”页签底部补齐法律信息入口和备案信息;同时在登录弹窗中增加协议确认,用户首次登录必须手动勾选同意后才能继续登录。
## 2. 入口与布局
### 2.1 “我的”页签常用功能
- 已登录用户在“我的”页签看到常用功能区。
- 常用功能区移动端和网页端都使用 3 列网格。
- 每个功能入口保持图标、主标题、短副标题结构。
- 不新增独立“我的”页面,只扩展现有个人页签。
### 2.2 法律信息区
法律信息区放在“我的”页签底部、设置入口之后。
区块内容:
- 区块标题:`法律信息`
- 三个列表入口:
- `用户协议`
- `隐私政策`
- `免责声明`
- 每个入口点击后打开独立模态面板,不在当前页签下方展开内容。
- 备案信息固定显示在法律入口下方:
- 文案:`京ICP备2026025677号`
- 点击跳转到 `https://beian.miit.gov.cn/`
- 外链在新窗口打开,并使用 `rel="noreferrer"`
## 3. 法律内容面板
### 3.1 内容来源
三份法律内容读取仓库现有 Markdown 文件:
- `media/files/user_agreement.md`
- `media/files/privacy_policy.md`
- `media/files/disclaimer.md`
### 3.2 展示规则
- 使用平台主题变量渲染,暗色和亮色主题都必须可读。
- 面板最大高度不超过视口,正文区域内部滚动。
- 标题固定在面板顶部,底部保留确认按钮 `我知道了`
- Markdown 首版只需要支持标题、段落、列表和加粗文本。
- 不把 Markdown 原文作为纯文本整段堆叠,必须保留基本阅读层级。
## 4. 登录协议确认
### 4.1 展示位置
登录弹窗的短信登录和密码登录表单都在提交按钮上方展示协议确认行:
`我已阅读并同意《用户协议》《隐私政策》和《免责声明》`
其中三段蓝色链接分别打开对应法律内容面板。
### 4.2 勾选规则
- 使用本地存储 key `genarrative.auth.legal-consent.v1` 记录是否已经确认。
- 首次打开登录弹窗时,如果没有本地确认记录,勾选框默认为未选中。
- 后续打开登录弹窗时,如果本地已有确认记录,勾选框默认为选中。
- 用户未勾选时:
- 登录按钮禁用。
- 点击法律链接只打开内容面板,不自动勾选。
- 用户勾选后:
- 立即写入本地确认记录。
- 短信登录和密码登录都可继续使用。
## 5. 验收
- 已登录“我的”页签常用功能区为 3 列。
- “我的”页签底部出现 `法律信息`、三个入口和 `京ICP备2026025677号`
- 三个法律入口都能打开独立可滚动面板。
- 备案号点击打开 `https://beian.miit.gov.cn/`
- 首次登录弹窗协议勾选为空,登录按钮禁用。
- 勾选协议后登录按钮恢复可用,并持久化本地确认状态。
- 再次打开登录弹窗时协议勾选默认选中。
## 6. 2026-05-12 落地记录
- 法律文档解析与弹窗复用 `src/components/common/legalDocuments.ts``src/components/common/LegalDocumentModal.tsx`
- “我的”页签在 `src/components/rpg-entry/RpgEntryHomeView.tsx` 中接入 3 列常用功能、法律入口和备案链接。
- 登录协议确认在 `src/components/auth/LoginScreen.tsx` 中接入,短信登录和密码登录共用同一确认行。
- 定向验证:
- `npm run test -- src/components/auth/AuthGate.test.tsx src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx`
- `npx eslint src/components/auth/LoginScreen.tsx src/components/auth/AuthGate.test.tsx src/components/common/LegalDocumentModal.tsx src/components/common/legalDocuments.ts src/components/rpg-entry/RpgEntryHomeView.tsx src/components/rpg-entry/RpgEntryHomeView.recharge.test.tsx --max-warnings 0`

View File

@@ -4,7 +4,9 @@
## 重点入口 ## 重点入口
- [AI 原生幕间文字游戏模板 PRD参考 MOKU 的剧本模拟器闭环](./AI_NATIVE_TEXT_GAME_TEMPLATE_MOKU_REFERENCE_PRD_2026-05-05.md)参考 MOKU / 幕间类 AI 文游的剧本游乐场、自由行动、AI GM、记忆和模拟器强反馈经验但只落为百梦 `text-game` 模板,复用平台接口,不迁入外部社区、支付、私有存档或回放 - [宝贝爱画寓教于乐独立关卡 PRD](./BABY_LOVE_DRAWING_EDUTAINMENT_LEVEL_PRD_2026-05-13.md)定义寓教于乐内容线的 `宝贝爱画` 独立本地 Demo 关卡,覆盖画板、七色选择、画笔/橡皮、手部绘画、完成、image-2 绘画魔法、本地保存和关闭入口隐藏边界
- [宝贝识物寓教于乐模板 PRD](./BABY_OBJECT_MATCH_EDUTAINMENT_TEMPLATE_PRD_2026-05-11.md):定义寓教于乐内容线的 `宝贝识物` 创作模板覆盖两个物品名称输入、image-2 物品图生成、精确 `寓教于乐` 标签、结果页和发布边界。
- [AI 原生幕间文字游戏模板 PRD参考 MOKU 的剧本模拟器闭环](./AI_NATIVE_TEXT_GAME_TEMPLATE_MOKU_REFERENCE_PRD_2026-05-05.md):参考 MOKU / 幕间类 AI 文游的剧本游乐场、自由行动、AI GM、记忆和模拟器强反馈经验但只落为陶泥儿 `text-game` 模板,复用平台接口,不迁入外部社区、支付、私有存档或回放。
- [AI 原生视觉小说模板 PRDTXT 玩法平台化接入](./AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.md):参考 `Interactive-fiction-backend` / `Interactive-fiction-frontend` 的 TXT 玩法经验,但只保留视觉小说模板创作与运行闭环,完全使用 Genarrative 平台接口,并明确删除回放和外部平台功能。 - [AI 原生视觉小说模板 PRDTXT 玩法平台化接入](./AI_NATIVE_VISUAL_NOVEL_TEMPLATE_PRD_2026-05-05.md):参考 `Interactive-fiction-backend` / `Interactive-fiction-frontend` 的 TXT 玩法经验,但只保留视觉小说模板创作与运行闭环,完全使用 Genarrative 平台接口,并明确删除回放和外部平台功能。
- [AI 原生幸存者类游戏模板 PRD](./AI_NATIVE_SURVIVOR_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-05.md):定义 `survivor` 幸存者挑战模板,从 Agent 创作、结果页、资产、试玩、发布到后端权威配置与前端高频运行表现的完整闭环。 - [AI 原生幸存者类游戏模板 PRD](./AI_NATIVE_SURVIVOR_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-05.md):定义 `survivor` 幸存者挑战模板,从 Agent 创作、结果页、资产、试玩、发布到后端权威配置与前端高频运行表现的完整闭环。
- [创意互动内容生成 Agent Phase 1 PRDLangChain-Rust PoC + 拼图闭环](./CREATIVE_INTERACTIVE_AGENT_PHASE1_LANGCHAIN_RUST_PUZZLE_LOOP_PRD_2026-05-05.md)首版只支持拼图模板Agent 使用 APIMart Responses `gpt-5` 支持文本和图像多模态输入,明确模板选择、积分范围、草稿字段填充、单关卡/多关卡图片生成、立即试玩、自然语言修改和可并行任务拆分。 - [创意互动内容生成 Agent Phase 1 PRDLangChain-Rust PoC + 拼图闭环](./CREATIVE_INTERACTIVE_AGENT_PHASE1_LANGCHAIN_RUST_PUZZLE_LOOP_PRD_2026-05-05.md)首版只支持拼图模板Agent 使用 APIMart Responses `gpt-5` 支持文本和图像多模态输入,明确模板选择、积分范围、草稿字段填充、单关卡/多关卡图片生成、立即试玩、自然语言修改和可并行任务拆分。
@@ -12,6 +14,7 @@
- [AI 原生拼图玩法创作工具与玩法系统 PRD](./AI_NATIVE_PUZZLE_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-22.md):拼图玩法创作、结果页、发布、广场和运行时主链路。 - [AI 原生拼图玩法创作工具与玩法系统 PRD](./AI_NATIVE_PUZZLE_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-22.md):拼图玩法创作、结果页、发布、广场和运行时主链路。
- [AI 原生方洞挑战玩法创作工具与玩法系统 PRD](./AI_NATIVE_SQUARE_HOLE_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-04.md):方洞挑战创作、发布与试玩闭环。 - [AI 原生方洞挑战玩法创作工具与玩法系统 PRD](./AI_NATIVE_SQUARE_HOLE_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-04.md):方洞挑战创作、发布与试玩闭环。
- [后台管理独立前端工程 PRD](./ADMIN_WEB_CONSOLE_PRD_2026-04-30.md):后台管理端产品边界。 - [后台管理独立前端工程 PRD](./ADMIN_WEB_CONSOLE_PRD_2026-04-30.md):后台管理端产品边界。
- [“我的”页签法律信息与登录协议确认 PRD](./PROFILE_LEGAL_INFO_AND_AUTH_AGREEMENT_PRD_2026-05-12.md):定义个人页法律入口、备案链接、法律内容弹窗和首次登录协议勾选规则。
## 使用规则 ## 使用规则

View File

@@ -37,7 +37,7 @@ TXT 模式核心玩法是一个包含“创作编辑器 -> 测试体验 -> 正
1. 支持创建 TXT 模式作品。 1. 支持创建 TXT 模式作品。
2. 支持 TXT 模式作品的完整创作流程。 2. 支持 TXT 模式作品的完整创作流程。
3. 支持百梦主测试体验。 3. 支持陶泥儿主测试体验。
4. 支持玩家正式游玩。 4. 支持玩家正式游玩。
5. 支持文本模式运行。 5. 支持文本模式运行。
6. 支持双会话机制。 6. 支持双会话机制。
@@ -176,9 +176,9 @@ TXT 模式核心玩法必须完整保留双会话机制。
2. 正式继续体验 2. 正式继续体验
3. 正式游玩推进 3. 正式游玩推进
## 7.2 百梦主测试/读档会话 ## 7.2 陶泥儿主测试/读档会话
百梦主测试/读档会话用于: 陶泥儿主测试/读档会话用于:
1. 编辑器内测试体验 1. 编辑器内测试体验
2. 指定存档加载 2. 指定存档加载

View File

@@ -2,7 +2,7 @@
> **For Hermes:** Use subagent-driven-development skill to implement this plan task-by-task. > **For Hermes:** Use subagent-driven-development skill to implement this plan task-by-task.
**Goal:**百梦后台新增“埋点数据”页,展示每条埋点原始事件的详细字段,并支持导出为 Excel 可直接打开的表格文件。 **Goal:**陶泥儿后台新增“埋点数据”页,展示每条埋点原始事件的详细字段,并支持导出为 Excel 可直接打开的表格文件。
**Architecture:** 后端继续由 `api-server` 作为后台 BFF经 SpacetimeDB HTTP SQL 只读查询 `tracking_event`,不改变表结构和 reducer。前端在 `apps/admin-web` 中新增独立路由与页面,页面渲染后端返回的原始明细,并在浏览器侧导出 Excel 兼容的 `.xls` HTML 表格,避免新增依赖。 **Architecture:** 后端继续由 `api-server` 作为后台 BFF经 SpacetimeDB HTTP SQL 只读查询 `tracking_event`,不改变表结构和 reducer。前端在 `apps/admin-web` 中新增独立路由与页面,页面渲染后端返回的原始明细,并在浏览器侧导出 Excel 兼容的 `.xls` HTML 表格,避免新增依赖。

View File

@@ -45,7 +45,7 @@
修复: 修复:
1.`map_password_entry_error(...)` 中补充 `InvalidPublicUserCode` 1.`map_password_entry_error(...)` 中补充 `InvalidPublicUserCode`
2. 返回中文错误文案 `百梦号格式不正确` 2. 返回中文错误文案 `陶泥号格式不正确`
### 3.3 `module-custom-world` 的 `Display` 分支未覆盖新字段错误 ### 3.3 `module-custom-world` 的 `Display` 分支未覆盖新字段错误

View File

@@ -34,9 +34,10 @@ GENARRATIVE_LLM_BASE_URL=
GENARRATIVE_LLM_API_KEY= GENARRATIVE_LLM_API_KEY=
GENARRATIVE_LLM_MODEL= GENARRATIVE_LLM_MODEL=
# APIMart / OpenAI 兼容 Responses 文本网关 # APIMart / OpenAI 兼容 Responses 文本网关与抓大鹅 nanobanana 物品素材图
APIMART_BASE_URL= APIMART_BASE_URL=
APIMART_API_KEY= APIMART_API_KEY=
APIMART_IMAGE_REQUEST_TIMEOUT_MS=180000
# VectorEngine / GPT-image-2 / Suno / Vidu 生成网关 # VectorEngine / GPT-image-2 / Suno / Vidu 生成网关
VECTOR_ENGINE_BASE_URL=https://api.vectorengine.ai VECTOR_ENGINE_BASE_URL=https://api.vectorengine.ai
@@ -101,11 +102,25 @@ HYPER3D_MODEL_REQUEST_TIMEOUT_MS / RODIN_MODEL_REQUEST_TIMEOUT_MS
3. 文本 LLM provider 为 `ark` 且未配置 `GENARRATIVE_LLM_BASE_URL` 时,仍回退到 Ark 公开基础 URL。 3. 文本 LLM provider 为 `ark` 且未配置 `GENARRATIVE_LLM_BASE_URL` 时,仍回退到 Ark 公开基础 URL。
4. 角色视频 provider 复用 Ark 且未配置 `ARK_CHARACTER_VIDEO_BASE_URL` 时,仍回退到 Ark 公开基础 URL。 4. 角色视频 provider 复用 Ark 且未配置 `ARK_CHARACTER_VIDEO_BASE_URL` 时,仍回退到 Ark 公开基础 URL。
5. 具体模型名缺失时不在配置层伪造默认模型,调用到对应能力时由下游配置校验返回缺配置错误。 5. 具体模型名缺失时不在配置层伪造默认模型,调用到对应能力时由下游配置校验返回缺配置错误。
6. VectorEngine 图片与音频生成只读取 `VECTOR_ENGINE_BASE_URL` / `VECTOR_ENGINE_API_KEY`,其中 GPT-image-2 图片生成额外读取 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS`;不复用 `APIMART_*``GENARRATIVE_LLM_*` 或前端变量。 6. VectorEngine 图片与音频生成只读取 `VECTOR_ENGINE_BASE_URL` / `VECTOR_ENGINE_API_KEY`,其中 GPT-image-2 图片生成额外读取 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS`;不复用 `APIMART_*``GENARRATIVE_LLM_*` 或前端变量。拼图 Agent 的生成 action 不做前端自动重试,避免一次点击在上游超时后重复触发外部生图与钱包扣退费;若 VectorEngine 请求达到该超时窗口api-server 返回 `504 Gateway Timeout``error.details.provider``vector-engine`,并保留具体超时 message。
7. 火山引擎语音能力由 `platform-speech` 收口协议帧与上游鉴权,`api-server` 只暴露平台鉴权后的代理路由,不向前端返回任何密钥字段。 7. 火山引擎语音能力由 `platform-speech` 收口协议帧与上游鉴权,`api-server` 只暴露平台鉴权后的代理路由,不向前端返回任何密钥字段。
8. Hyper3D Rodin Gen-2 使用公开默认 `https://api.hyper3d.com/api/v2`API Key 只读取 `HYPER3D_API_KEY` / `RODIN_API_KEY`,不复用文本 LLM、图片或音频网关密钥。 8. Hyper3D Rodin Gen-2 使用公开默认 `https://api.hyper3d.com/api/v2`API Key 只读取 `HYPER3D_API_KEY` / `RODIN_API_KEY`,不复用文本 LLM、图片或音频网关密钥。
9. APIMart 当前保留给创意 Agent 的 `gpt-5` Responses 文本/多模态理解链路GPT-image-2 图片生成不得读取 APIMart 配置。 9. APIMart 当前保留给创意 Agent 的 `gpt-5` Responses 文本/多模态理解链路,并用于抓大鹅物品素材 sheet 的 `nanobanana2` / Gemini 图片模型GPT-image-2 图片生成不得读取 APIMart 配置。
10. 本地 `npm run api-server``npm run dev:rust``npm run dev` 的环境文件优先级固定为外层 shell 变量最高,其后 `.env``.env.local``.env.secrets.local` 逐层覆盖;真实密钥建议放在 `.env.secrets.local`,防止 `.env` 中的空示例值覆盖私密配置。 10. 本地 `npm run api-server``npm run dev:rust``npm run dev``npm run dev:web` 的环境文件优先级固定为非空外层 shell 变量最高,其后 `.env``.env.local``.env.secrets.local` 逐层覆盖;真实密钥建议放在 `.env.secrets.local`,防止 `.env` 中的空示例值覆盖私密配置。外层 shell 变量如果是空字符串或全空白,不再遮蔽本地 env 文件中的真实值。
11. OSS 客户端只在 `ALIYUN_OSS_BUCKET``ALIYUN_OSS_ENDPOINT``ALIYUN_OSS_ACCESS_KEY_ID``ALIYUN_OSS_ACCESS_KEY_SECRET` 四项齐全时初始化。四项全部缺失表示未启用 OSS部分缺失时 `api-server` 记录 warning 并继续启动,具体上传、换签或读取 generated 私有资产的接口返回 `OSS 未完成环境变量配置`,并在 `error.details.missingEnv` 中列出缺失变量。
12. 抓大鹅 2D 草稿素材生成需要同时具备 APIMart、VectorEngine 与 OSS 配置APIMart `gemini-3.1-flash-image-preview` 负责生成 5x5 物品素材 sheetVectorEngine `gpt-image-2-all` 负责封面、9:16 背景图和 1:1 容器 UI 图OSS 负责保存切割后的五视角图片及其它生成图。缺少 APIMart、VectorEngine 或 OSS 时应通过 `error.details.reason` 向前端暴露具体缺项,不能只显示泛化“服务暂不可用”。素材图、封面图和背景图生成在调用外部生图前必须先预检 OSS避免已消耗外部生图后才发现无法落库。
13. 拼图有参考图且开启 AI 重绘时使用 VectorEngine `POST /v1/images/edits` multipart 接口。若返回 `error sending request for url`,代表后端未收到 HTTP 响应;响应 `details` 会带 `reason``source``connect``body``timeout``endpoint`排查时优先检查服务器网络、DNS、防火墙、代理和参考图大小。拼图图片客户端强制 HTTP/1.1,以降低上游 multipart HTTP/2 连接中断风险。
14. 本地排查 `OSS 未完成环境变量配置` 时必须核对键名是否精确为 `ALIYUN_OSS_ACCESS_KEY_SECRET`。常见误写是把 `OSS` 的首字母 `O` 写成数字 `0`,例如 `ALIYUN_0SS_ACCESS_KEY_SECRET`;该键不会被 `api-server` 读取。
## 本地配置检查
拼图真实生成同时依赖 VectorEngine 与 OSS。触发生成前可先运行
```bash
npm run check:api-server-env
```
该命令只输出配置项是否存在,不打印密钥值。若显示 `ALIYUN_0SS_*`,说明把 `OSS` 的字母 `O` 写成了数字 `0`。修正 env 文件后必须重启 `npm run api-server``npm run dev`,已经运行中的 `api-server` 进程不会自动读取新的环境变量。
## 示例文件 ## 示例文件

View File

@@ -1,8 +1,8 @@
# 资产操作点消耗接入方案 # 资产操作点消耗接入方案
## 背景 ## 背景
当前点钱包余额、充值流水与邀请奖励已经收口到 `server-rs/crates/spacetime-module/src/runtime/profile.rs`。资产图片生成和作品发布由 Axum API 调用外部模型或写入业务状态SpacetimeDB reducer/procedure 不能直接执行外部网络生成,因此计费需要拆成两层: 当前点钱包余额、充值流水与邀请奖励已经收口到 `server-rs/crates/spacetime-module/src/runtime/profile.rs`。资产图片生成和作品发布由 Axum API 调用外部模型或写入业务状态SpacetimeDB reducer/procedure 不能直接执行外部网络生成,因此计费需要拆成两层:
- SpacetimeDB 负责钱包余额和流水的原子变更。 - SpacetimeDB 负责钱包余额和流水的原子变更。
- Axum 资产操作服务负责在执行业务资产操作前扣费,并在生成、持久化或发布失败时补偿退款。 - Axum 资产操作服务负责在执行业务资产操作前扣费,并在生成、持久化或发布失败时补偿退款。
@@ -20,17 +20,23 @@
- Big Fish Agent 动作 `big_fish_publish_game` - Big Fish Agent 动作 `big_fish_publish_game`
- Puzzle Agent 图片生成动作 `compile_puzzle_draft``generate_puzzle_images` - Puzzle Agent 图片生成动作 `compile_puzzle_draft``generate_puzzle_images`
- Puzzle Agent 动作 `publish_puzzle_work` - Puzzle Agent 动作 `publish_puzzle_work`
- Match3D / 抓大鹅草稿生成动作 `match3d_compile_draft`
- 拼图 / 抓大鹅结果页手动生成背景音乐、UI 背景与抓大鹅批量新增物品素材
暂不接入以下入口: 暂不接入以下入口:
- 旧资产工坊角色主形象/动作生成接口:当前仍使用 `asset-tool` 作为兼容归属,无法确认真实用户。 - 旧资产工坊角色主形象/动作生成接口:当前仍使用 `asset-tool` 作为兼容归属,无法确认真实用户。
- 手动上传封面:不调用外部生成模型,不消耗点。 - 手动上传封面:不调用外部生成模型,不消耗点。
- 自定义世界草稿自动补图链路:属于后台补全流程,避免一次用户操作触发多笔不可预期扣费。 - 自定义世界草稿自动补图链路:属于后台补全流程,避免一次用户操作触发多笔不可预期扣费。
- 文本实体、NPC 生成:本次需求聚焦图片资产和发布资产操作,首期只覆盖可明确归属的入口。 - 文本实体、NPC 生成:本次需求聚焦图片资产和发布资产操作,首期只覆盖可明确归属的入口。
## 计费规则 ## 计费规则
- 每次可计费资产操作消耗 `1`点。 - 每次可计费资产操作消耗 `1`点。
- 例外Match3D / 抓大鹅草稿生成是一次完整草稿外部生成动作,固定消耗 `10` 枚泥点;流水仍复用 `asset_operation_consume` / `asset_operation_refund``asset_kind = match3d_draft_generation`
- 例外:拼图 / 抓大鹅背景音乐生成固定消耗 `5` 枚泥点;物品点击音效仍按单个音效任务消耗 `10` 枚泥点。
- 例外:拼图 / 抓大鹅 UI 背景重新生成固定消耗 `2` 枚泥点。
- 例外:抓大鹅结果页批量新增物品素材按实际可新增物品名计费,每 `5` 个消耗 `2` 枚泥点,不足 `5` 个向上按 `5` 个计。重复名称、作品中已有名称和超过容量上限的名称不进入计费数量。
- 图片生成和作品发布都按资产操作计费;余额不足时禁止继续执行。 - 图片生成和作品发布都按资产操作计费;余额不足时禁止继续执行。
- 在调用外部图片生成或发布 mutation 前预扣,余额不足时直接返回业务错误,不继续调用后续资产操作。 - 在调用外部图片生成或发布 mutation 前预扣,余额不足时直接返回业务错误,不继续调用后续资产操作。
- 如果图片生成、远程下载、OSS 写入、资产记录确认或发布 mutation 失败,资产操作服务自动发起同额退款。 - 如果图片生成、远程下载、OSS 写入、资产记录确认或发布 mutation 失败,资产操作服务自动发起同额退款。
@@ -38,10 +44,10 @@
## 钱包流水 ## 钱包流水
公开两个流水来源类型,统一覆盖“资产生成”和“资产发布”这两类资产操作: 公开两个流水来源类型,统一覆盖“资产生成”和“资产发布”这两类资产操作。流水金额由具体资产操作成本决定,不再假定所有资产操作都是 `1` 枚泥点
- `asset_operation_consume`:资产操作预扣,`amount_delta = -1` - `asset_operation_consume`:资产操作预扣,`amount_delta = -points_cost`
- `asset_operation_refund`:资产操作失败退款,`amount_delta = +1` - `asset_operation_refund`:资产操作失败退款,`amount_delta = +points_cost`
`wallet_ledger_id` 由 Axum 传入,格式: `wallet_ledger_id` 由 Axum 传入,格式:

View File

@@ -10,6 +10,7 @@
2. 当前设备识别方式与 `isCurrent` 语义 2. 当前设备识别方式与 `isCurrent` 语义
3. 多端登录识别字段如何从 `refresh_session` 派生到 DTO 3. 多端登录识别字段如何从 `refresh_session` 派生到 DTO
4. Rust 首版在 Axum + 进程内 `module-auth` 下的最小实现边界 4. Rust 首版在 Axum + 进程内 `module-auth` 下的最小实现边界
5. `2026-05-13` 会话组合并展示与远端踢下线闭环修复口径
## 2. 当前基线 ## 2. 当前基线
@@ -46,11 +47,16 @@
3. 登录创建 session 时落库结构化客户端身份字段 3. 登录创建 session 时落库结构化客户端身份字段
4. 会话列表返回多端识别所需字段,并兼容旧 `clientLabel` 4. 会话列表返回多端识别所需字段,并兼容旧 `clientLabel`
本阶段明确不包含 `2026-05-13` 起,本接口同时承担账号安全页的会话组读模型
1. `/api/auth/sessions/:sessionId/revoke` 1. 后端按“同设备 + 同 IP”聚合活跃 `refresh_session`
2. 前端完整消费全部新增字段 2. 前端只消费后端聚合结果,不自行推断合并
3. SpacetimeDB reducer / view 正式读表 3. `POST /api/auth/sessions/{sessionId}/revoke` 已纳入 Rust 实现,用于踢下线非当前会话
本阶段仍明确不包含:
1. SpacetimeDB reducer / view 正式读表
2. 登录方式、refresh token 轮换策略或账号安全页整体重设计
## 5. 请求与响应 contract ## 5. 请求与响应 contract
@@ -70,6 +76,8 @@
"sessions": [ "sessions": [
{ {
"sessionId": "usess_xxx", "sessionId": "usess_xxx",
"sessionIds": ["usess_xxx", "usess_yyy"],
"sessionCount": 2,
"clientType": "web_browser", "clientType": "web_browser",
"clientRuntime": "chrome", "clientRuntime": "chrome",
"clientPlatform": "windows", "clientPlatform": "windows",
@@ -90,9 +98,12 @@
字段说明: 字段说明:
1. `clientLabel` 当前阶段继续兼容旧前端字段,值固定与 `deviceDisplayName` 保持一致 1. `sessionId` 是聚合组代表会话 ID若组内包含当前 `sid`,代表 ID 必须使用当前会话 ID
2. `clientRuntime``clientPlatform``deviceDisplayName` 是多端识别首版最小新增字段 2. `sessionIds` 是该聚合组内全部活跃 session ID前端批量踢下线时逐个调用 revoke
3. 小程序来源额外暴露 `miniProgramAppId``miniProgramEnv` 3. `sessionCount` 是聚合组内 session 数量
4. `clientLabel` 当前阶段继续兼容旧前端字段,值固定与 `deviceDisplayName` 保持一致
5. `clientRuntime``clientPlatform``deviceDisplayName` 是多端识别首版最小新增字段
6. 小程序来源额外暴露 `miniProgramAppId``miniProgramEnv`
### 5.3 失败响应 ### 5.3 失败响应
@@ -110,12 +121,25 @@
1. 从 refresh cookie 读取当前原始 refresh token 1. 从 refresh cookie 读取当前原始 refresh token
2. 在 Axum 侧计算 `sha256(refresh_token)` 2. 在 Axum 侧计算 `sha256(refresh_token)`
3. 与会话列表中的 `refresh_token_hash` 比较 3. 与会话列表中的 `refresh_token_hash` 比较
4. 命中则 `isCurrent = true` 4. 同时读取 Bearer access token claims 中的 `sid`
5. 聚合组内任意 session 命中当前 refresh hash 或当前 `sid`,则整组 `isCurrent = true`
说明: 说明:
1. 如果请求没有携带 refresh cookie本接口仍可返回会话列表 1. 如果请求没有携带 refresh cookie本接口仍可返回会话列表
2. 此时全部会话的 `isCurrent` 都为 `false` 2. 此时仍可通过 Bearer `sid` 标记当前组
3. 当前组不允许在前端显示“踢下线”,当前设备退出必须走 `/api/auth/logout`
## 6.1 会话组合并规则
同设备同 IP 的 active refresh sessions 在后端合并为一条 DTO
1. 优先使用 `device_fingerprint + ip` 作为聚合 key
2.`device_fingerprint` 时退化为 `client_type + client_runtime + client_platform + device_display_name + user_agent + ip`
3. `createdAt` 取组内最早 `created_at`
4. `lastSeenAt` 取组内最新 `last_seen_at`
5. `expiresAt` 取组内最新 `expires_at`
6. `ipMasked` 仍只返回脱敏 IP
## 7. 多端标识派生规则 ## 7. 多端标识派生规则
@@ -161,8 +185,21 @@
负责: 负责:
1. 读取 Bearer JWT 与 refresh cookie 1. 读取 Bearer JWT 与 refresh cookie
2. 把活跃会话映射成旧接口兼容 DTO 2. 按同设备同 IP 聚合活跃会话
3. 派生 `ipMasked``isCurrent` 3. 把活跃会话组映射成旧接口兼容 DTO
4. 派生 `ipMasked``isCurrent`
5. 暴露 `POST /api/auth/sessions/{sessionId}/revoke`
## 8.3 指定会话吊销接口
`POST /api/auth/sessions/{sessionId}/revoke` 固定规则:
1. Bearer JWT 必填
2. 仅允许吊销当前用户自己的非当前会话
3. 当前会话自吊销返回业务错误,提示使用退出登录
4. 只撤销目标 `refresh_session`,不递增 `token_version`
5. 撤销后同步 auth store 到 SpacetimeDB
6. 认证中间件会校验 access token `sid` 对应 active `refresh_session`,因此被踢设备已有 access token 会立即失效
## 9. 测试策略 ## 9. 测试策略
@@ -172,6 +209,9 @@
2. 微信内 H5 登录后,会话列表返回 `wechat_h5 + wechat_embedded_browser` 2. 微信内 H5 登录后,会话列表返回 `wechat_h5 + wechat_embedded_browser`
3. 显式小程序头优先于 `User-Agent` 判断 3. 显式小程序头优先于 `User-Agent` 判断
4. 请求携带当前 refresh cookie 时,只有当前会话 `isCurrent = true` 4. 请求携带当前 refresh cookie 时,只有当前会话 `isCurrent = true`
5. 同设备同 IP 会话会合并,并返回 `sessionIds/sessionCount`
6. 合并组包含当前 `sid` 或当前 refresh hash 时,整组 `isCurrent = true`
7. 指定远端会话吊销后,被踢设备 access token 立即无法通过认证
## 10. 完成定义 ## 10. 完成定义
@@ -181,4 +221,6 @@
2. 会话列表可区分普通浏览器、微信内 H5、小程序来源 2. 会话列表可区分普通浏览器、微信内 H5、小程序来源
3. 同设备不同浏览器可在会话列表中清晰区分 3. 同设备不同浏览器可在会话列表中清晰区分
4. `clientLabel` 与新增多端字段都已稳定返回 4. `clientLabel` 与新增多端字段都已稳定返回
5. 文档、任务清单与测试已同步更新 5. 同设备同 IP 的重复 active refresh sessions 已合并展示
6. 非当前会话可通过真实 revoke 接口踢下线
7. 文档、任务清单与测试已同步更新

View File

@@ -40,12 +40,12 @@ HTTP status server error (503 Service Unavailable)
### 3.1 认证快照同步改为非阻断 ### 3.1 认证快照同步改为非阻断
`AppState::sync_auth_store_snapshot_to_spacetime` 保持导出本地快照、写入 SpacetimeDB、导入正式表的顺序但当远端写入或导入失败时只写 warn 日志并返回 `Ok(())` `AppState::sync_auth_store_snapshot_to_spacetime` 保持导出本地认证快照,但运行期会直接调用 `import_auth_store_snapshot_json` 覆盖导入 SpacetimeDB 正式认证表,不再刷新 `auth_store_snapshot/default`;当远端导入失败时只写 warn 日志并返回 `Ok(())`
设计边界: 设计边界:
1. 当前认证请求的即时真相源是本地 `auth_store` 1. 当前认证请求的即时真相源是本地 `auth_store`
2. SpacetimeDB 认证快照用于跨进程恢复和正式表投影 2. SpacetimeDB 正式认证表用于跨进程恢复`auth_store_snapshot/default` 只保留为历史迁移和兜底恢复记录
3. 远端库挂起或网络异常只降级远端恢复能力,不回滚已经成功的登录、刷新、退出和资料更新。 3. 远端库挂起或网络异常只降级远端恢复能力,不回滚已经成功的登录、刷新、退出和资料更新。
### 3.2 Vite 补齐创作接口代理 ### 3.2 Vite 补齐创作接口代理
@@ -98,10 +98,25 @@ npm run dev:web
1. `GET http://127.0.0.1:3000/api/auth/login-options` 返回 `["phone","password"]` 1. `GET http://127.0.0.1:3000/api/auth/login-options` 返回 `["phone","password"]`
2. `GET http://127.0.0.1:3000/api/runtime/match3d/gallery` 返回 `{"items":[]}`,不再返回 SpacetimeDB 503。 2. `GET http://127.0.0.1:3000/api/runtime/match3d/gallery` 返回 `{"items":[]}`,不再返回 SpacetimeDB 503。
3. 未登录请求 `POST http://127.0.0.1:3000/api/creation/match3d/sessions` 返回 `401`,说明同源请求已进入 Rust 鉴权层,不再被 Vite `404` 3. 未登录请求 `POST http://127.0.0.1:3000/api/creation/match3d/sessions` 返回 `401`,说明同源请求已进入 Rust 鉴权层,不再被 Vite `404`
4. 隔离端口指向挂起的远端库并使用 mock 短信时,手机号验证码登录返回 `200` 和 token日志只记录“认证快照入 SpacetimeDB 失败,当前认证流程继续”。 4. 隔离端口指向挂起的远端库并使用 mock 短信时,手机号验证码登录返回 `200` 和 token日志只记录“认证快照入 SpacetimeDB 正式表失败,当前认证流程继续”。
## 6. 后续 ## 6. 后续
1. 远端 `xushi-p4wfr` 仍需恢复数据库挂起状态,否则对应玩法 procedure 仍不可用。 1. 远端 `xushi-p4wfr` 仍需恢复数据库挂起状态,否则对应玩法 procedure 仍不可用。
2. 本地开发如只为体验抓大鹅,可继续使用本地 SpacetimeDB 链路。 2. 本地开发如只为体验抓大鹅,可继续使用本地 SpacetimeDB 链路。
3. 认证快照同步失败会影响进程重启后的远端恢复完整性,需要在目标库恢复后重新完成一次成功同步。 3. 认证快照同步失败会影响进程重启后的远端恢复完整性,需要在目标库恢复后重新完成一次成功同步。
## 7. 2026-05-13 补充:服务暂不可用的分层排查
抓大鹅生成页只看到“服务暂不可用”时,不应先回退旧 3D / Rodin 链路,应按 2D 素材生成链路逐层定位:
1. 前端通用 API 错误展示必须读取 `error.details.reason`。VectorEngine、OSS 等配置缺失类错误常把具体原因写在 `details.reason`,如果只读 `details.message`,用户只能看到泛化的“服务暂不可用”。
2. `api-server` 启动不应被 OSS 半配置阻断。`ALIYUN_OSS_BUCKET` / `ALIYUN_OSS_ENDPOINT` 已配置但 `ALIYUN_OSS_ACCESS_KEY_ID` / `ALIYUN_OSS_ACCESS_KEY_SECRET` 缺失时,服务应记录 warning 并跳过 OSS 客户端初始化;需要上传或读取 generated 私有资产的接口继续返回 `OSS 未完成环境变量配置`,并通过 `details.missingEnv` 明确缺少哪几项。
3. 启动阶段从 SpacetimeDB 恢复认证快照只能降级远端恢复能力,不能长期卡住 `/healthz`。本地库未发布、连接后立即 close 或远端库挂起时,`api-server` 应在启动恢复超时后使用本地 `auth_store` 继续进入监听。
4. 抓大鹅真实生成仍依赖两组私密配置:`VECTOR_ENGINE_BASE_URL` / `VECTOR_ENGINE_API_KEY` 用于 `gpt-image-2-all` 生成 1K 素材图;完整 `ALIYUN_OSS_*` 四件套用于上传切割后的 `generated-match3d-assets` 五视角图片。缺任一组都应返回明确 `details.reason`;抓大鹅素材、封面和背景生成在调用 VectorEngine 前先预检 OSS不应先消耗生图调用再失败也不应恢复 GLB 生成。
验证时以实际 `GENARRATIVE_API_PORT` 为准;本地 `.env.local` 可能覆盖脚本默认 `3100`。例如当前本地端口为 `8082` 时,应请求:
```powershell
Invoke-WebRequest -UseBasicParsing http://127.0.0.1:8082/healthz
```

View File

@@ -6,8 +6,9 @@
落地口径: 落地口径:
- `user_account``auth_identity``refresh_session` 作为 SpacetimeDB 中的正式认证持久化表。 - `user_account``auth_identity``refresh_session` 作为 SpacetimeDB 中的正式认证持久化表。
- `auth_store_projection_meta` 只记录正式认证表最近一次由认证快照导入的时间,不保存用户快照内容。
- API 启动时优先从正式表导出兼容 `module-auth` 的认证快照,再恢复到内存认证服务。 - API 启动时优先从正式表导出兼容 `module-auth` 的认证快照,再恢复到内存认证服务。
- 运行期认证变更仍先复用现有 `module-auth` 逻辑生成一致快照,随后同步快照并导入正式表,保证正式表与快照一致 - 运行期认证变更仍先复用现有 `module-auth` 逻辑生成一致快照,随后调用 `import_auth_store_snapshot_json` 直接覆盖导入正式表;不再继续刷新 `auth_store_snapshot/default`
- 本阶段不重写登录、刷新、登出内部业务规则,避免在 JWT、refresh rotation、微信绑定合并等复杂语义中引入行为漂移。 - 本阶段不重写登录、刷新、登出内部业务规则,避免在 JWT、refresh rotation、微信绑定合并等复杂语义中引入行为漂移。
## 2. 非目标 ## 2. 非目标
@@ -21,7 +22,7 @@
### 3.1 启动恢复 ### 3.1 启动恢复
1. API 调用 `export_auth_store_snapshot_from_tables` 1. API 调用 `export_auth_store_snapshot_from_tables`
2. 若正式表已有用户、身份或会话数据,则返回兼容 `module-auth` 的 JSON 快照。 2. 若正式表已有用户、身份或会话数据,则返回兼容 `module-auth` 的 JSON 快照,并带上 `auth_store_projection_meta/default.updated_at`
3. API 用 `InMemoryAuthStore::from_snapshot_json` 恢复认证服务。 3. API 用 `InMemoryAuthStore::from_snapshot_json` 恢复认证服务。
4. 若正式表为空或调用失败,则回退到 Stage 1 的 `auth_store_snapshot` 4. 若正式表为空或调用失败,则回退到 Stage 1 的 `auth_store_snapshot`
5. 若 Stage 1 也不可用,则回退本地 JSON 热修复文件。 5. 若 Stage 1 也不可用,则回退本地 JSON 热修复文件。
@@ -29,9 +30,10 @@
### 3.2 运行期同步 ### 3.2 运行期同步
1. 登录、刷新、登出等路径继续调用当前内存认证服务。 1. 登录、刷新、登出等路径继续调用当前内存认证服务。
2. 每次认证状态变更后调用 `upsert_auth_store_snapshot` 2. 每次认证状态变更后导出当前内存认证快照 JSON
3. 快照写入成功后调用 `import_auth_store_snapshot`,覆盖导入正式表 3. API 调用 `import_auth_store_snapshot_json`,在同一 SpacetimeDB transaction 中清空并重建 `user_account/auth_identity/refresh_session`,同时更新 `auth_store_projection_meta/default.updated_at`
4. 导入失败时返回错误,避免用户误以为状态已经持久化 4. `upsert_auth_store_snapshot``import_auth_store_snapshot` 保留为旧库迁移入口,只服务 `auth_store_snapshot/default` 到正式认证表的历史导入,不作为运行期同步路径
5. 远端导入失败只记录 warn 并继续当前认证响应,避免远端库挂起时回滚已经成功的登录、刷新、退出和资料更新。
## 4. 数据重建规则 ## 4. 数据重建规则

View File

@@ -23,7 +23,7 @@ Stage 1 已把 Rust 鉴权快照同步到 SpacetimeDB 的 `auth_store_snapshot`
1. `POST /api/auth/refresh` 改写 `refresh_session` 表。 1. `POST /api/auth/refresh` 改写 `refresh_session` 表。
2. 登录成功写 `user_account/auth_identity/refresh_session` 2. 登录成功写 `user_account/auth_identity/refresh_session`
3. `logout/logout-all/revoke-session` 改写细粒度表。 3. `logout/logout-all/revoke-session` 改写细粒度表。
4. `auth_store_snapshot` 退化为迁移备份。 4. `auth_store_snapshot` 退化为迁移备份;运行期若仍复用内存认证快照,也应通过 `import_auth_store_snapshot_json` 直接导入正式认证表,不再刷新 `auth_store_snapshot/default`
## 3. 表设计落地口径 ## 3. 表设计落地口径
@@ -34,7 +34,7 @@ Stage 1 已把 Rust 鉴权快照同步到 SpacetimeDB 的 `auth_store_snapshot`
| 字段 | 类型 | 说明 | | 字段 | 类型 | 说明 |
| --- | --- | --- | | --- | --- | --- |
| `user_id` | `String` | 主键。 | | `user_id` | `String` | 主键。 |
| `public_user_code` | `String` | 公开百梦号。 | | `public_user_code` | `String` | 公开陶泥号。 |
| `username` | `String` | 当前账号用户名。 | | `username` | `String` | 当前账号用户名。 |
| `display_name` | `String` | 展示名。 | | `display_name` | `String` | 展示名。 |
| `phone_number_masked` | `Option<String>` | 脱敏手机号。 | | `phone_number_masked` | `Option<String>` | 脱敏手机号。 |
@@ -94,4 +94,3 @@ Stage 1 已把 Rust 鉴权快照同步到 SpacetimeDB 的 `auth_store_snapshot`
2. Rust bindings 已刷新。 2. Rust bindings 已刷新。
3. `spacetime-client` 暴露导入 procedure facade。 3. `spacetime-client` 暴露导入 procedure facade。
4. `api-server/spacetime-client/module-auth` 定向检查通过。 4. `api-server/spacetime-client/module-auth` 定向检查通过。

View File

@@ -0,0 +1,202 @@
# 宝贝爱画本地 Demo 运行态实现方案 2026-05-13
## 1. 范围
本方案落地寓教于乐独立关卡:
```text
baby-love-drawing / 宝贝爱画
```
当前范围只做本地 Demo 闭环:
1. 寓教于乐频道默认关卡卡片;
2. 独立运行态;
3. mocap 与开发者调试输入;
4. Canvas 绘制和擦除;
5. image-2 绘画魔法后端代理;
6. localStorage 本地保存;
7. 直达路由开关保护。
本阶段不接正式持久化表,不新增作品发布、作品号、公开详情或搜索入口。
## 2. 前端接入点
已新增页面阶段:
```text
baby-love-drawing-runtime
```
已新增路由:
```text
/runtime/baby-love-drawing
```
已新增文件:
```text
packages/shared/src/contracts/edutainmentBabyDrawing.ts
src/services/edutainment-baby-drawing/babyDrawingClient.ts
src/components/edutainment-runtime/babyLoveDrawingModel.ts
src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.tsx
server-rs/crates/api-server/src/edutainment_baby_drawing.rs
```
已接入:
1. `src/components/rpg-entry/RpgEntryHomeView.tsx`:寓教于乐频道默认展示宝贝爱画卡片;
2. `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`:启动宝贝爱画运行态;
3. `src/components/platform-entry/platformEntryTypes.ts`:扩展 `SelectionStage`
4. `src/routing/appPageRoutes.ts`:扩展路由;
5. `src/routing/appRoutes.tsx`:直达路由开关保护;
6. `src/index.css`:补齐寓教于乐默认关卡卡片和宝贝爱画运行态样式;
7. `server-rs/crates/api-server/src/app.rs`:挂载绘画魔法后端路由。
## 3. 契约
契约放在:
```text
packages/shared/src/contracts/edutainmentBabyDrawing.ts
```
核心字段:
1. `templateId = "baby-love-drawing"`
2. `templateName = "宝贝爱画"`
3. `originalImageSrc` 保存原始画布图;
4. `magicImageSrc` 保存 image-2 魔法图,可为 `null`
5. `strokeTrace` 保存画笔和橡皮轨迹;
6. `saveMode = "original-only" | "original-and-magic"` 记录保存结果。
## 4. 运行态模型
运行态状态:
```text
drawing
finished
magicPending
magicReady
saved
```
工具:
```text
brush
eraser
```
颜色:
```text
红、橙、黄、绿、青、蓝、紫
```
按钮悬停:
1. 颜色选择只接受左手悬停,阈值 1500ms
2. 按钮选择接受任一手悬停,阈值 2000ms
3. 工具切换只接受右手在工具区域握拳。
4. 画笔 / 橡皮光标位置只接受右手坐标;左手缺帧或左手移动不得重置、替换或驱动画笔位置。
5. 左手需要显示独立位置指示器,帮助用户确认当前是否悬停在目标颜色上;该指示器只表达左手位置,不参与画笔 / 橡皮操作。
6. 本地 mocap handedness 当前按摄像头视角输出,宝贝爱画运行态消费前需要换算为用户身体视角:`rightHand` 作为用户左手,`leftHand` 作为用户右手。键鼠调试输入不做该换算。
7. 真实硬件短暂缺失某只手时,显示层保留上一帧位置约 320ms 并做轻微坐标平滑;绘制层仍只在当前帧确认用户右手存在时生效。
8. 为避免左手抢画笔,本关不做动态 handedness 换手纠正;`rightHand` 永远只进入用户左手选色通道,`leftHand` 永远只进入用户右手画笔通道。若硬件侧 handedness 继续抖动,宁可右手画笔短暂停住,也不允许左手驱动画笔。
9. 右手画笔通道增加单帧最大位移门禁;若 camera-left 候选点相对上一帧右手位置出现不合理大跳,判定为不可信帧,只保留上一帧光标并停止绘制。
## 5. Canvas 绘制
画板使用 DOM Canvas。
绘制规则:
1. 右手在画板内且状态为 `grab` 时生效;
2. 工具为 `brush` 时,以当前颜色绘制连续线段;
3. 工具为 `eraser` 时,以 `destination-out` 擦除;
4. 右手状态为 `open_palm` 或离开画板时结束当前笔画;
5. 当前帧没有右手坐标时只结束当前笔画,不把左手坐标用于绘制、擦除或光标定位;
6. 每条笔画记录工具、颜色、点位和时间。
## 6. 绘画魔法
前端 service
```text
createBabyDrawingMagicImage(payload)
```
后端接口:
```text
POST /api/creation/edutainment/baby-love-drawing/magic
```
请求体:
```json
{
"originalImageSrc": "data:image/png;base64,...",
"strokeTrace": []
}
```
响应体:
```json
{
"magicImageSrc": "data:image/png;base64,...",
"generationProvider": "vector-engine-gpt-image-2",
"prompt": "..."
}
```
后端使用 VectorEngine `gpt-image-2-all`,把原始画布图作为参考图,生成绘本风格图片。
本地未配置 VectorEngine 或接口失败时,前端允许提示错误并保留原图保存能力;不得把失败伪装成正式魔法图。
后端接入约束:
1. 接口需要 Bearer 鉴权;
2. 请求体限制为 8MB
3. `originalImageSrc` 只接受图片 Data URL
4. 笔触数量上限为 600 条;
5. 上游参考图字段使用 VectorEngine 统一契约 `image`
6. 关闭入口时,`creation_entry_config` 路由熔断可识别 `baby-love-drawing`
## 7. 本地保存
本地保存使用:
```text
localStorage key = genarrative.edutainmentBabyDrawing.localDrawings.v1
```
保存策略:
1. 魔法生成前保存:`saveMode = "original-only"`,只保存 `originalImageSrc`
2. 未保存原图直接生成魔法后保存:`saveMode = "original-and-magic"`,保存 `originalImageSrc``magicImageSrc`
3. 保存后展示“再画一张”和“返回”。
## 8. 验收命令
```bash
npm run test -- src/components/edutainment-runtime/babyLoveDrawingModel.test.ts src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.test.tsx src/services/edutainment-baby-drawing/babyDrawingClient.test.ts src/routing/appRoutes.test.ts
cargo test -p api-server edutainment_baby_drawing --manifest-path server-rs/Cargo.toml
cargo test -p api-server resolves_runtime_paths_to_creation_type_ids --manifest-path server-rs/Cargo.toml
npx eslint src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.tsx src/components/edutainment-runtime/babyLoveDrawingModel.ts src/services/edutainment-baby-drawing/babyDrawingClient.ts src/routing/appRoutes.tsx --ext .ts,.tsx --max-warnings 0
npm run typecheck
npm run check:encoding
```
## 9. 已覆盖测试
1. `src/components/edutainment-runtime/babyLoveDrawingModel.test.ts`:颜色 / 按钮悬停阈值、坐标归一化、笔触追加;
2. `src/components/edutainment-runtime/BabyLoveDrawingRuntimeShell.test.tsx`:画板、七色、画笔 / 橡皮、完成保存、返回按钮、左手位置指示器、mocap 摄像头视角到用户身体视角换算、左手输入不替换画笔光标位置、左手短暂缺帧不闪烁、用户左手不能抢占右手画笔、camera-left 大跳不接入画笔;
3. `src/services/edutainment-baby-drawing/babyDrawingClient.test.ts`:原图保存、原图加魔法图保存、后端魔法接口请求;
4. `src/routing/appRoutes.test.ts``/runtime/baby-love-drawing` 开启可达、关闭回落主应用;
5. `server-rs/crates/api-server/src/edutainment_baby_drawing.rs` 内部单测prompt、Data URL 校验、PNG 输出和轨迹范围摘要;
6. `server-rs/crates/api-server/src/creation_entry_config.rs` 路由映射单测:确认后端熔断可识别 `baby-love-drawing`

View File

@@ -0,0 +1,252 @@
# 宝贝识物创作发布实现方案 2026-05-11
## 1. 范围
本方案对应第 2 线程:创作发布线程。
本线程落地:
1. 创作入口配置;
2. 模板表单;
3. 本地草稿生成 service
4. 结果页;
5. 发布 payload 约束;
6. 本地 Demo 运行态;
7. 后端 image-2 / 作品持久化 / 运行态接口预留形状。
本阶段运行态先做浏览器本地 Demo并消费现有本地 mocap 动作数据源;正式硬件接口和摄像头调教在后续接口稳定后继续接入。
## 2. 前端接入点
新增玩法 ID
```text
baby-object-match
```
用户展示名:
```text
宝贝识物
```
工程接入文件:
1. `server-rs/crates/spacetime-module/src/runtime/creation_entry_config.rs`
2. `src/components/platform-entry/platformEntryCreationTypes.ts`
3. `src/components/platform-entry/PlatformEntryCreationTypeModal.tsx`
4. `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
`src/config/newWorkEntryConfig.ts` 已迁移删除,不再作为入口事实源。`baby-object-match` 必须存在于 SpacetimeDB `creation_entry_type_config` 默认种子中,默认展示名为 `宝贝识物``visible=true``open=true``sortOrder=90`;前端只通过 `GET /api/creation-entry/config` 读取后端配置并在 `platformEntryCreationTypes.ts` 做展示派生。
`baby-object-match` 必须复用 `VITE_ENABLE_EDUTAINMENT_ENTRY` 开关;开关关闭时,创作类型弹层不展示 `宝贝识物`,创作页作品架不展示本地宝贝识物草稿或已发布作品卡,公开发现、搜索、详情、作品号和浏览历史也继续完全不可见。
新增阶段:
```text
baby-object-match-workspace
baby-object-match-generating
baby-object-match-result
baby-object-match-runtime
```
## 3. 契约
前端共享契约放在:
```text
packages/shared/src/contracts/edutainmentBabyObject.ts
```
核心字段:
1. `BabyObjectMatchDraft.templateId = "baby-object-match"`
2. `BabyObjectMatchDraft.templateName = "宝贝识物"`
3. `BabyObjectMatchDraft.themeTags` 必须包含精确 `寓教于乐`
4. `BabyObjectMatchItemAsset.generationProvider` 首版允许为 `vector-engine-gpt-image-2``placeholder`
5. `BabyObjectMatchDraft.visualPackage` 可选承载背景环境、UI 装饰框、礼物盒、篮子和烟雾弹出特效五类视觉资源;
6. `BabyObjectMatchPublishRequest.draft.themeTags` 发布前必须归一化补齐 `寓教于乐`
## 4. Service 边界
前端 service 放在:
```text
src/services/edutainment-baby-object/babyObjectMatchClient.ts
```
首版提供:
1. `createBabyObjectMatchDraft(payload)`
2. `saveBabyObjectMatchDraft(draft)`
3. `publishBabyObjectMatchWork(payload)`
4. `deleteLocalBabyObjectMatchDraft(profileId)`
5. `regenerateBabyObjectMatchDraftAssets(draft)`
6. `hasBabyObjectMatchPlaceholderAssets(draft)`
当前后端正式作品持久化接口未在本线程扩表落地,因此 service 仍使用本地 Demo 存储草稿和发布状态。由于 image-2 会返回多张 base64 PNG 大图,本地 Demo 草稿必须优先写入 IndexedDB `genarrative-edutainment-baby-object-drafts/drafts`,不得把完整草稿 JSON 写入 `localStorage``localStorage` 仅作为旧版小草稿迁移读取来源,读取后迁移到 IndexedDB 并清理旧 key避免触发浏览器 `Storage` 配额错误。
物品图片生成已接入后端 image-2 接口:
```text
POST /api/creation/edutainment/baby-object-match/assets
```
请求体:
```json
{
"itemNames": ["苹果", "香蕉"]
}
```
响应体:
```json
{
"assets": [
{
"itemId": "baby-object-item-1",
"itemName": "苹果",
"imageSrc": "data:image/png;base64,...",
"assetObjectId": null,
"generationProvider": "vector-engine-gpt-image-2",
"prompt": "..."
}
],
"visualPackage": {
"themePrompt": "...",
"assets": [
{
"assetId": "baby-object-visual-background",
"assetKind": "background",
"imageSrc": "data:image/png;base64,...",
"assetObjectId": null,
"generationProvider": "vector-engine-gpt-image-2",
"prompt": "..."
}
]
}
}
```
该接口返回物品透明 PNG data URL以及同一次创作生成的视觉主题包。本地 Demo 阶段暂不写入 OSS 或 SpacetimeDB `asset_object`。当前创作链路必须真实拿到 `generationProvider = "vector-engine-gpt-image-2"` 的物品图和视觉主题包后才允许进入结果页;若本地未配置 VectorEngine、登录态失效、接口返回 401/5xx、上游生成失败或响应缺少任一资源前端 service 必须抛出错误并停留在生成失败状态,不得静默回退到占位图。
由于一次创作会生成 2 张物品图和 `background``ui-frame``gift-box``basket``smoke-puff` 5 张视觉包装图,该请求属于长耗时 image-2 链路。前端 `babyObjectMatchClient` 对该 POST 使用 10 分钟请求超时,且不做自动重试,避免第一次生成仍在后端执行时又发起第二次重复生成。后端同时启动物品图与视觉主题包生成,并把该路由的 VectorEngine 单图请求等待预算提升到至少 8 分钟,避免某张图 3 分钟附近仍在生成时被后端提前断开。后端日志记录每类资源的开始、完成和耗时,排查时优先按同一次 HTTP 请求查看 `宝贝识物 image-2 物品资源生成完成``宝贝识物 image-2 视觉资源生成完成``VectorEngine 图片生成上游错误`
历史本地草稿中若已保存 `generationProvider = "placeholder"` 的旧占位资源,结果页必须提示“重新生成 image-2 资源”,并禁用试玩和发布。用户点击重新生成、发布或试玩前,前端统一调用 `regenerateBabyObjectMatchDraftAssets(draft)` 补齐资源;补齐失败时保留在结果页并展示错误。
后续正式作品持久化接入时,应补齐:
```text
POST /api/creation/edutainment/baby-object-match/drafts
PUT /api/creation/edutainment/baby-object-match/drafts/{draftId}
POST /api/creation/edutainment/baby-object-match/drafts/{draftId}/publish
```
图片生成必须在后端调用 VectorEngine `gpt-image-2-all`,不得从前端直接调用外部图片接口。
后端 image-2 prompt 约束:
1. 锁定寓教于乐板块统一的卡通绘本草地舞台插画风;
2. 每张图只能围绕对应关键词生成一个单一物品;
3. 不生成背景、场景、氛围渲染、人物、手、篮子、礼物盒、文字、水印或 UI
4. 优先要求纯白或透明抠图友好的干净背景,服务端再统一转透明 PNG 并执行背景 alpha 清理;
5. 返回 `generationProvider = "vector-engine-gpt-image-2"` 的素材必须已经完成透明抠图。
后端视觉主题包 prompt 约束:
1. 同一次请求根据两个物品关键词生成 `background``ui-frame``gift-box``basket``smoke-puff` 五类资源;
2. 总风格继续锁定寓教于乐明亮卡通绘本插画风;
3. 若关键词偏动漫角色、玩具或公仔,背景环境和 UI 元素匹配动漫、玩具主题;若关键词偏水果,匹配果园、自然主题;其它关键词按语义匹配合适主题;
4. 背景环境图使用非透明 16:9 图,但必须保证中间、中下方和底部左右篮子区域清爽,给放大后的礼物盒、中央物品和左右篮子预留空间,不画入礼物盒、篮子、物品、人物、文字或操作 UI
5. UI 装饰框、礼物盒、篮子和烟雾弹出特效使用透明 PNG 后处理,不生成文字、数字、按钮、人物或待分类物品;
6. `gift-box` 提示词必须面向运行态约 2 倍视觉尺寸生成主体饱满的大号礼物盒,`basket` 提示词必须面向运行态约 1.5 倍视觉尺寸生成可读性高的大号篮子;
7. `smoke-puff` 只生成礼物盒打开瞬间使用的柔和烟雾云朵特效,不生成礼物盒、篮子、物品或文字;
8. 左右篮子的固定选项规则不受主题包影响,运行态只把 `basket` 作为篮子造型包装复用。
## 5. UI 边界
工作台只展示两个必填输入和生成按钮。
结果页只展示草稿核心信息、两个物品、保存草稿、发布、试玩。不在 UI 内写玩法说明长文案。
移动端优先:表单和结果页使用单列布局,桌面端自然扩展为双列。
## 6. 运行态边界
前端运行态放在:
```text
src/components/edutainment-runtime/BabyObjectMatchRuntimeShell.tsx
```
运行态直接消费 `BabyObjectMatchDraft`,必须使用草稿中的两个物品名称和物品图。
每轮只随机当前从礼物盒跳出的物品;左右篮子不随机交换,左侧固定为草稿 `itemAssets[0]`,右侧固定为草稿 `itemAssets[1]`
若草稿包含 `visualPackage`运行态通过背景图片层、CSS 变量和图片节点消费:
1. `background`:作为舞台最底层 `ResolvedAssetImage` 背景图;存在该资源时必须关闭默认草地兜底层,避免生成场景被 CSS 草地遮住或弱化;
2. `ui-frame`:作为字幕条和计数器装饰背景;
3. `gift-box`:替换 CSS 礼物盒主体,按旧视觉约 2 倍尺寸展示,只在礼盒入场和打开阶段存在;
4. `basket`:替换篮子主体造型,按旧视觉约 1.5 倍尺寸展示,左右两侧复用同一张主题篮子图;
5. `smoke-puff`:作为礼物盒打开和中央物品弹出期间的透明烟雾特效资源。
旧草稿或接口失败时 `visualPackage = null`,运行态继续使用现有 CSS 绘本风兜底。
首关状态机:
1. `gift-entering`:礼物盒从上方落下入场动画阶段,不接受动作判定;
2. `gift-opening`:礼物盒打开并播放烟雾特效阶段,不接受动作判定;
3. `item-appearing`:礼物盒从舞台移除,当前物品从烟雾中出现并停稳,不接受动作判定;
4. `active`:物品彻底出现后才开放选篮判定;
5. `correct`:展示“真棒”反馈,对应篮筐播放正确特效并停顿,成功次数加 1特效完全结束后重新进入 `gift-entering`,下一轮礼物盒从上方落下;
6. `wrong`:展示“再想一想吧”反馈,物品弹回中央;反馈结束后回到 `active`,不重新随机物品;
7. `complete`:成功次数达到 20展示“恭喜你小朋友”和按钮。
动作输入:
1. 左手连续横向移动达到阈值:将当前物品送入左侧篮子;
2. 右手连续横向移动达到阈值:将当前物品送入右侧篮子。
运行态直接通过 `useMocapInput` 消费本地 mocap WebSocket `/stream`。选篮只使用明确 `leftHand``rightHand` 的连续横向轨迹阈值,不再通过 `wave_left_hand``wave_right_hand``wave` 等动作名触发;侧别为 `unknown` 的手部轨迹也不参与选篮,以避免多套判定误命中和连续误触发。动作判定只在 `active` 阶段开放,礼盒入场、礼盒打开、物品出现、正确反馈和错误反馈阶段收到的动作包必须清空轨迹并忽略,不允许跨阶段补判定。当前本地 mocap 输出的 handedness 按摄像头视角标记,宝贝识物运行态必须先换算为用户身体视角:`rightHand` 轨迹映射玩家左手并进入左侧篮子,`leftHand` 轨迹映射玩家右手并进入右侧篮子。草稿试玩、发布后正式体验和热身关后的本地 Demo 都复用同一个运行态,因此三条入口都必须具备同一套动作控制能力。
开发者调试输入:
1. 鼠标左键按下并拖动:映射左手轨迹,抬起后将当前物品送入左侧篮子;
2. 鼠标右键按下并拖动:映射右手轨迹,抬起后将当前物品送入右侧篮子。
运行态不得新增计时、失败次数、分数、体力或难度递增规则。
音效和语音播报当前只保留接口预留边界,正式语音接口后续接入。
## 7. 发布约束
发布前必须执行:
1. 两个物品名非空;
2. 两个物品名对应的 asset 存在;
3. 标签补齐精确 `寓教于乐`
4. `publicationStatus``draft` 变为 `published`
发布后首版本地响应返回 `publicWorkCode`,用于分享弹窗;正式后端接入时 public code 生成规则需要纳入统一作品号服务。
## 8. 热身关衔接
`/child-motion-demo` 热身完成后的“开始游戏”按钮进入同一个 `BabyObjectMatchRuntimeShell`
热身关独立 Demo 没有创作者草稿上下文,因此使用固定本地 Demo 草稿承载两个物品,仅用于热身关后验证首关体验;正式平台体验仍必须从 `宝贝识物` 模板创作发布后进入寓教于乐板块。
## 9. 验收命令
```bash
npm run test -- src/components/platform-entry/platformEntryCreationTypes.test.ts src/components/edutainment-creation/BabyObjectMatchWorkspace.test.tsx src/components/edutainment-result/BabyObjectMatchResultView.test.tsx src/components/edutainment-runtime/BabyObjectMatchRuntimeShell.test.tsx src/components/child-motion-demo/ChildMotionWarmupDemo.test.tsx src/services/edutainment-baby-object/babyObjectMatchClient.test.ts
cargo test -p api-server edutainment_baby_object --manifest-path server-rs/Cargo.toml
npx vitest run src/components/platform-entry/platformEdutainmentVisibility.test.ts src/components/platform-entry/PlatformWorkDetailView.test.tsx src/components/custom-world-home/creationWorkShelf.test.ts src/services/useMocapInput.test.ts src/services/child-motion-demo/childMotionDebugInput.test.ts src/routing/appRoutes.test.ts
npx eslint src/components/platform-entry/platformEntryCreationTypes.ts src/components/platform-entry/platformEntryCreationTypes.test.ts src/components/platform-entry/PlatformEntryFlowShellImpl.tsx --ext .ts,.tsx --max-warnings 0
npm run check:encoding
npm run typecheck
npm run build:raw
```
若后续接入真实 Rust API 和 SpacetimeDB 表,再补充 `npm run api-server``/healthz`、Rust contract / api-server / spacetime-client 定向测试和 migration 表目录更新。

View File

@@ -94,6 +94,7 @@ API Server 新增统一 helper
| `auth_phone_login_success` | `POST /api/auth/phone/login` | | `auth_phone_login_success` | `POST /api/auth/phone/login` |
| `auth_me_view` | `GET /api/auth/me` | | `auth_me_view` | `GET /api/auth/me` |
| `auth_sessions_view` | `GET /api/auth/sessions` | | `auth_sessions_view` | `GET /api/auth/sessions` |
| `auth_revoke_session` | `POST /api/auth/sessions/{session_id}/revoke` |
| `auth_refresh_success` | `POST /api/auth/refresh` | | `auth_refresh_success` | `POST /api/auth/refresh` |
| `auth_logout` | `POST /api/auth/logout` | | `auth_logout` | `POST /api/auth/logout` |
| `auth_logout_all` | `POST /api/auth/logout-all` | | `auth_logout_all` | `POST /api/auth/logout-all` |

View File

@@ -47,7 +47,7 @@
用户完成热身关所有步骤后,进入关卡选择。 用户完成热身关所有步骤后,进入关卡选择。
当前后续游戏仍在设计中。热身结束后可先展示“开始游戏”按钮作为关卡选择占位,用户点击后进入下一关占位界面 热身结束后展示“开始游戏”按钮,用户点击后进入宝贝识物首关本地 Demo。该入口只用于热身关后的本地体验验证正式平台体验仍必须通过“宝贝识物”创作模板发布后在寓教于乐板块进入
### 3.3 固定流程顺序 ### 3.3 固定流程顺序
@@ -170,6 +170,9 @@
3. 位置类状态必须满足“到达绿色圆环并保持 2 秒”。 3. 位置类状态必须满足“到达绿色圆环并保持 2 秒”。
4. 动作类状态没有最长等待时间。 4. 动作类状态没有最长等待时间。
5. 动作类状态等待 3 秒后可以播放对应引导动画。 5. 动作类状态等待 3 秒后可以播放对应引导动画。
6. 每个步骤进入时需要先展示本步骤文字字幕和语音播报入口,约 1 秒后再进入可交互阶段并展示绿色圆环、手势引导等检测提示。
7. 步骤完成后需要先进入完成停顿阶段,当前停顿约 0.8 秒;停顿期间保留完成反馈位置,后续可在该阶段补充完成特效或音效,再切换到下一步骤。
8. 入场等待和完成停顿阶段不消费动作完成判定,避免用户上一步残留动作直接触发下一步。
### 6.3 开发者调试输入 ### 6.3 开发者调试输入
@@ -368,6 +371,17 @@
用户完成挥动左手。 用户完成挥动左手。
当前本地 mocap 的 handedness 按摄像头视角输出,热身关内需要先换算成用户身体视角再判断:摄像头右侧手对应用户左手。挥动左手不是普通横向轨迹检测,而是用于确认现实环境中用户左侧手臂打开空间足够和安全。
完成条件必须同时满足:
1. 使用用户身体左手轨迹。
2. 手腕在左肩外侧达到最小外展距离。
3. 手腕不能处于自然下垂低位。
4. 最近连续有效帧中,手臂存在足够上下摆动幅度。
5. 最近连续有效帧中,肩膀到手腕向量的角度变化达到阈值。
6. 至少出现一次上下摆动方向变化。
#### 完成反馈 #### 完成反馈
```text ```text
@@ -376,7 +390,7 @@
#### 数据记录 #### 数据记录
记录用户挥动左手的空间,保存为该用户对应的行为坐标。 记录用户挥动左手的轨迹、空间包络、角度范围和最大外展距离,保存为该用户对应的行为坐标。
--- ---
@@ -398,6 +412,17 @@
用户完成挥动右手。 用户完成挥动右手。
当前本地 mocap 的 handedness 按摄像头视角输出,热身关内需要先换算成用户身体视角再判断:摄像头左侧手对应用户右手。挥动右手不是普通横向轨迹检测,而是用于确认现实环境中用户右侧手臂打开空间足够和安全。
完成条件必须同时满足:
1. 使用用户身体右手轨迹。
2. 手腕在右肩外侧达到最小外展距离。
3. 手腕不能处于自然下垂低位。
4. 最近连续有效帧中,手臂存在足够上下摆动幅度。
5. 最近连续有效帧中,肩膀到手腕向量的角度变化达到阈值。
6. 至少出现一次上下摆动方向变化。
#### 完成反馈 #### 完成反馈
```text ```text
@@ -406,7 +431,7 @@
#### 数据记录 #### 数据记录
记录用户挥动右手的空间,保存为该用户对应的行为坐标。 记录用户挥动右手的轨迹、空间包络、角度范围和最大外展距离,保存为该用户对应的行为坐标。
--- ---
@@ -642,7 +667,7 @@
1. `src/ChildMotionDemoApp.tsx` 挂载独立 Demo 应用壳。 1. `src/ChildMotionDemoApp.tsx` 挂载独立 Demo 应用壳。
2. `src/components/child-motion-demo/childMotionWarmupModel.ts` 维护热身步骤、圆环目标、2 秒保持判定、热身校准记录和当前运行时会话完成标记。 2. `src/components/child-motion-demo/childMotionWarmupModel.ts` 维护热身步骤、圆环目标、2 秒保持判定、热身校准记录和当前运行时会话完成标记。
3. `src/components/child-motion-demo/ChildMotionWarmupDemo.tsx` 实现横屏舞台、背景虚化占位层、角色剪影、绿色圆环、手势引导、热身记录面板、热身完成后的“开始游戏”按钮和下一关占位界面 3. `src/components/child-motion-demo/ChildMotionWarmupDemo.tsx` 实现横屏舞台、背景虚化占位层、角色剪影、绿色圆环、手势引导、热身记录面板、热身完成后的“开始游戏”按钮,并复用宝贝识物运行态进入首关本地 Demo
4. `src/services/child-motion-demo/childMotionDebugInput.ts` 保留开发者调试输入适配层,后续可被正式动作识别 SDK 适配层替换或并行接入。 4. `src/services/child-motion-demo/childMotionDebugInput.ts` 保留开发者调试输入适配层,后续可被正式动作识别 SDK 适配层替换或并行接入。
5. `src/routing/appRoutes.tsx` 新增 `/child-motion-demo` 独立路由,并复用 `VITE_ENABLE_EDUTAINMENT_ENTRY` 开关;开关关闭时不允许通过该直达路径进入 Demo。 5. `src/routing/appRoutes.tsx` 新增 `/child-motion-demo` 独立路由,并复用 `VITE_ENABLE_EDUTAINMENT_ENTRY` 开关;开关关闭时不允许通过该直达路径进入 Demo。
@@ -653,35 +678,49 @@
3. 鼠标左键按下并拖动映射左手轨迹。 3. 鼠标左键按下并拖动映射左手轨迹。
4. 鼠标右键按下并拖动映射右手轨迹。 4. 鼠标右键按下并拖动映射右手轨迹。
5. 空格键映射原地跳跃。 5. 空格键映射原地跳跃。
6. 调试输入只在步骤可交互阶段触发步骤完成;步骤入场字幕阶段和完成停顿阶段会忽略完成判定,便于观察节奏和后续补充特效。
当前硬件和动作检测接口接入: 当前硬件和动作检测接口接入:
1. 浏览器摄像头视频流已接入舞台背景。 1. 浏览器摄像头视频流已接入舞台背景。
2. 热身关全流程已通过 `src/services/useMocapInput.ts` 接入本地 mocap WebSocket `/stream`;动作数据源状态优先于浏览器背景摄像头状态展示。 2. 热身关全流程已通过 `src/services/useMocapInput.ts` 接入本地 mocap WebSocket `/stream`;动作数据源状态优先于浏览器背景摄像头状态展示。
3. mocap 包支持从 `general.body.center_norm` 读取身体中心,位置类步骤使用该身体中心更新角色剪影横向位置并完成圆环保持检测。 3. mocap 包支持从 `general.body.center_norm` 读取身体中心,位置类步骤使用该身体中心更新角色剪影横向位置并完成圆环保持检测。
4. mocap 包支持从 `actions/action/gesture/gestures/event/name/type` 读取动作名,并支持 `hands[]``leftHand/rightHand``left_hand/right_hand` 读取左右手坐标。 4. 身体中心横向坐标进入角色剪影前必须做输入稳定化处理:先 clamp 到 `0..1`,再使用小幅死区、低通阻尼和单包最大步长限制,避免硬件噪声造成角色左右误判、画面抽搐或视觉上的忽大忽小。当前实现参数为死区 `0.012`、阻尼系数 `0.28`、单包最大步长 `0.035`;位置保持检测使用稳定化后的角色坐标。
5. `hands[].landmarks` 存在时优先用手腕和 MCP 点计算掌心中心;掌心点不足时退回 wrist landmark再退回 hand 直出坐标 5. 角色剪影渲染需要把水平位移和跳跃表现拆开:外层只负责横向定位,内层资源只负责轮廓图和跳跃位移,避免 `left``transform` 同时抢占导致半透明资源重采样抖动
6. `wave_greeting` 可由 `wave/wave_greeting/hand_wave/open_palm` 等动作或 open palm 手势完成 6. mocap 包支持从 `actions/action/gesture/gestures/event/name/type` 读取动作名,并支持 `hands[]``leftHand/rightHand``left_hand/right_hand` 读取左右手坐标
7. `wave_left_hand``wave_right_hand` 优先消费对应左右手动作名;当硬件只持续输出手部坐标时,也可以根据连续手部横向轨迹完成挥手检测 7. `hands[].landmarks` 存在时优先用手腕和 MCP 点计算掌心中心;掌心点不足时退回 wrist landmark再退回 hand 直出坐标
8. `jump_once` 消费 `jump/jump_once/hop` 等跳跃动作事件完成 8. `wave_greeting` 消费左手、右手或未知单手的连续横向挥手轨迹,不再使用 `wave``hand_wave``open_palm`、张手状态或动作名直接完成判定;进入轨迹判定前必须先满足抬手有效区:优先使用 `hands[].landmarks.wrist``general.limb_nodes` 的同侧 `*_elbow` / `*_shoulder` 判断,当前阈值为 `wrist.y <= elbow.y + 0.04`,缺少肘部时使用 `wrist.y <= shoulder.y + 0.08`;缺少同侧肘部和肩膀参考时不允许招呼通过,不再使用身体中心兜底判断抬手。轨迹阈值为至少 5 个连续抬手点,横向 `x` 范围差值不小于 `0.075`,且至少出现 1 次横向方向变化,避免“手刚露出画面”或“手自然下垂抖动”被误判为招手
9. 键盘 `A/D/Space` 与鼠标左右键拖拽仍保留为本地 Demo 调试兜底,不代表正式硬件口径 9. `wave_left_hand``wave_right_hand` 只消费用户身体侧对应手的连续坐标轨迹,不再使用动作名、张手状态或 primary hand 兜底完成判定;本地 mocap handedness 当前按摄像头视角输出,因此用户左手使用 camera-right用户右手使用 camera-left。完成判定必须同时满足对应肩肘腕外展、手腕非自然下垂、连续有效帧、横向范围、上下摆动范围、肩腕角度范围和上下方向变化当前阈值为连续外展点不少于 5 个、横向 `x` 范围不小于 `0.055`、垂直 `y` 范围不小于 `0.08`、肩腕角度范围不小于 `28°`、外展距离不小于 `0.12`、手腕相对肩膀外侧距离不小于 `0.1`;后续以真实体验结果继续调参
10. `jump_once` 消费 `jump/jump_once/hop` 等跳跃动作事件完成。
11. 键盘 `A/D/Space` 与鼠标左右键拖拽仍保留为本地 Demo 调试兜底,不代表正式硬件口径。
当前未接入但已保留边界: 当前未接入但已保留边界:
1. 正式语音播报接口暂不接入,当前先展示热身文案。 1. 正式语音播报接口暂不接入,当前先展示热身文案。
2. 正式 gpt-image-2 视觉资源暂不接入,当前使用 CSS 占位表达相同位置和状态 2. 后续关卡安全边界暂停逻辑暂未落地,当前只完成热身记录和宝贝识物首关本地 Demo 衔接
3. 后续关卡安全边界暂停逻辑暂未落地,当前只完成热身记录和下一关按钮占位。
## 16. 当前视觉资产与生图口径补充 ## 16. 当前视觉资产与生图口径补充
儿童动作 Demo 的视觉口径已经统一收敛到绘本风格草地舞台: 儿童动作 Demo 的视觉口径已经统一收敛到绘本风格草地舞台:
1. 舞台主环境采用卡通绘本风格、明亮草地、天空、小山坡和树木的组合,默认背景环境需要保证中心与下方前景留空,便于角色轮廓和地面指示环叠加。 1. 舞台主环境采用卡通绘本风格、明亮草地、天空、小山坡和树木的组合,默认背景环境需要保证中心与下方前景留空,便于角色轮廓和地面指示环叠加。
2. `src/index.css` 中的热身舞台、摄像头背景层、地面、角色轮廓、地面圆环、开始按钮和横屏提示均按绘本草地风格重做,未生成真实背景图时由 CSS 兜底 2. 该卡通绘本草地风格是儿童动作 Demo 后续场景、物品、UI 资源的全局风格要求;新增资源不得切回暗色科技风、真实照片风或后台面板风
3. 真实背景图的默认输出路径固定为 `public/child-motion-demo/picture-book-grass-stage.webp` 3. `src/index.css` 中的热身舞台、摄像头背景层、地面、角色轮廓、地面圆环、开始按钮和横屏提示均按绘本草地风格接入真实资源;资源加载失败时保留 CSS 兜底
4. 生成脚本固定为 `scripts/generate-child-motion-demo-assets.mjs`,并通过 `npm run assets:child-motion-demo` 触发;脚本使用 `gpt-image-2-all` 调用 VectorEngine `POST /v1/images/generations` 4. 生成脚本固定为 `scripts/generate-child-motion-demo-assets.mjs`,并通过 `npm run assets:child-motion-demo` 触发;脚本使用 `gpt-image-2-all` 调用 VectorEngine `POST /v1/images/generations`,透明资源先生成品红底源图,再在本地移除色键,源图写入 `tmp/child-motion-demo-assets/`
5. 当前本机工作区未检测到 `VECTOR_ENGINE_BASE_URL``VECTOR_ENGINE_API_KEY`,因此暂时只能完成 dry-run 或代码层接入,不能直接产出真实 image-2 资产。 5. 当前已生成并接入以下正式 Demo 资源:
6. 若后续补齐 VectorEngine 私密配置,再运行 live 生成即可把真实绘本背景写入上述固定路径,页面会自动读取 - `public/child-motion-demo/picture-book-grass-stage.png`:默认草地舞台背景
- `public/child-motion-demo/picture-book-foreground-grass-v2.png`:底部前景草坪条,只覆盖舞台下沿,不作为整块地板拉伸。
- `public/child-motion-demo/picture-book-ground-ring-v3.png`已按透视绘制的浅蓝与暖黄色地面椭圆指示环和草地材质做明显区分CSS 只等比缩放。
- `public/child-motion-demo/picture-book-character-outline-v2.png`:半透明用户角色轮廓,使用独立去背后处理避免内部填充被误删。
- `public/child-motion-demo/picture-book-hud-strip-v2.png`:顶部 HUD 细长软纸条。
- `public/child-motion-demo/picture-book-calibration-strip-v2.png`:右下角五格热身状态条。
- `public/child-motion-demo/picture-book-start-panel-v2.png`:开始按钮背后的轻盈托盘。
- `public/child-motion-demo/picture-book-ui-button-v2.png`:开始按钮绘本风按钮底图。
- `public/child-motion-demo/picture-book-wave-cat-body-guide-v6.png`:招手阶段中央猫咪身体底座资源,按可动纸偶结构只包含猫头、短身体和肩部连接点,不再和旧猫头、胸口或猫爪资源叠加。
- `public/child-motion-demo/picture-book-wave-cat-arm-guide-v6.png`:招手阶段左右独立手臂资源,也用于左右手阶段单手提示;网页用同一拆件镜像复用,并围绕肩部挂点做挥手摆动动画。
6. v2 资源按最终用途拆分CSS 必须按资源原始比例、`aspect-ratio``background-size: contain / auto` 等方式等比使用;禁止把方形面板强行拉伸为 HUD、状态条或地板也禁止把底部草坪扩展成覆盖角色脚下的大色块。
7. 猫咪招手引导资源使用 `cat-guide` 透明后处理:先由 image-2 生成品红底源图,再通过边缘背景连通区域去背,避免把浅粉、淡橘和暖棕主体误删。源图只保存在 `tmp/child-motion-demo-assets/`,正式页面只引用 `public/child-motion-demo/` 下的最终 PNG。
8. 若后续补充或重绘资源,应先运行 `npm run assets:child-motion-demo -- --dry-run` 核对 prompt 和输出路径,再使用 `--live --only <asset-id>` 小批量生成;仅调整透明去背、裁切、画布归一或品红边缘时,可用 `npm run assets:child-motion-demo -- --live --postprocess-only --force --only <asset-id>` 复用 `tmp/child-motion-demo-assets/` 中的源图,不额外请求 image-2不得把 `VECTOR_ENGINE_API_KEY`、源图或中间预览图提交到仓库。
已执行的定向验证命令: 已执行的定向验证命令:

View File

@@ -43,4 +43,7 @@
1. 创作中心三类作品仍在同一个网格展示。 1. 创作中心三类作品仍在同一个网格展示。
2. 草稿 / 已发布筛选计数统一从 `CreationWorkShelfItem.status` 读取。 2. 草稿 / 已发布筛选计数统一从 `CreationWorkShelfItem.status` 读取。
3. 卡片渲染不再直接判断 `publicationStatus` 或不同 works schema 的标题字段。 3. 卡片渲染不再直接判断 `publicationStatus` 或不同 works schema 的标题字段。
4. 现有创作中心交互测试通过。 4. 统一货架按 `updatedAt` 倒序排序,兼容 ISO 字符串和 `seconds.microsZ` 后端时间文本。
5. 作品卡片以 `coverImageSrc` 作为整卡背景;若 `coverImageSrc` 为空,允许从同一作品已有的关卡图、背景图或素材图兜底,避免草稿页退回普通面板视觉。
6. 卡片不展示最后修改时间,`updatedAt` 只参与排序。
7. 现有创作中心交互测试通过。

View File

@@ -582,7 +582,7 @@ puzzle_creative_level_generation_plan
- Agent 选择理由 - Agent 选择理由
- 支持单关卡、多关卡或二者皆可 - 支持单关卡、多关卡或二者皆可
- 计划关卡数 - 计划关卡数
- 预计积分范围,例如 `预计消耗 8 到 18 点` - 预计积分范围,例如 `预计消耗 8 到 18 点`
积分范围来自拼图模板协议: 积分范围来自拼图模板协议:

View File

@@ -1,4 +1,4 @@
# 自定义世界草稿场景幕事件与任务字段落地设计2026-04-25 # 自定义世界草稿场景幕事件与任务字段落地设计2026-04-25
## 背景 ## 背景
@@ -37,7 +37,7 @@
- 当前场景的核心任务描述。 - 当前场景的核心任务描述。
- 文本会作为游戏中首次进入某个场景生成章节任务的关键上下文。 - 文本会作为游戏中首次进入某个场景生成章节任务的关键上下文。
- 必须结合场景描述、场景入口钩子、出场角色与 3 幕事件,说明玩家首次进入该场景时要完成什么。 - 必须结合场景描述、场景入口钩子、出场角色与 3 幕事件,说明玩家首次进入该场景时要完成什么。
- 世界档案的场景详情页必须直接展示该字段,便于百梦主确认每个场景的默认章节任务。 - 世界档案的场景详情页必须直接展示该字段,便于陶泥儿主确认每个场景的默认章节任务。
### Landmark 生成源字段 ### Landmark 生成源字段

View File

@@ -32,6 +32,8 @@ process didn't exit successfully: `server-rs\target\debug\api-server.exe`
主站和后台 Vite 也追加 `--strictPort`,避免默认漂移到 `3001``3103` 等端口后让浏览器继续访问旧页面。 主站和后台 Vite 也追加 `--strictPort`,避免默认漂移到 `3001``3103` 等端口后让浏览器继续访问旧页面。
`--skip-spacetime` 是复用既有 SpacetimeDB 宿主的模式。该模式下脚本不会再把 SpacetimeDB 端口纳入可用性漂移;如果传入 `--spacetime-port 3101`,后端就会连接 `http://127.0.0.1:3101`。这可以避免 `3101` 已有 SpacetimeDB 在线时,端口工具误把它当作冲突并改到空闲的 `3102`,导致 api-server 连接空端口后 `/api/creation-entry/config`、作品架和公开图库接口同时返回 `502`
## 排障步骤 ## 排障步骤
PowerShell 查看默认端口占用: PowerShell 查看默认端口占用:
@@ -72,3 +74,4 @@ node scripts/run-bash-script.mjs scripts/dev-rust-stack.sh \
1. `bash -n scripts/dev-rust-stack.sh` 通过。 1. `bash -n scripts/dev-rust-stack.sh` 通过。
2. 默认端口被占用时重新运行完整栈,脚本应在 publish 前失败并打印占用进程。 2. 默认端口被占用时重新运行完整栈,脚本应在 publish 前失败并打印占用进程。
3. 清理占用进程或换端口后,重新启动时不再出现 Vite 端口漂移或 `api-server` `AddrInUse` 3. 清理占用进程或换端口后,重新启动时不再出现 Vite 端口漂移或 `api-server` `AddrInUse`
4. 复用 SpacetimeDB 时执行 `npm run dev -- --skip-spacetime --skip-publish --spacetime-port 3101`,启动日志里的 `[dev:rust] spacetime:` 应保持为 `http://127.0.0.1:3101`,并且 `GET /api/creation-entry/config` 不应因连接 `3102` 这类空端口而失败。

View File

@@ -408,7 +408,7 @@ Node 侧入口位于:
## 10.2 2026-05-01 新用户注册赠送修正 ## 10.2 2026-05-01 新用户注册赠送修正
新注册用户默认获得 `10`点,注册链路通过 SpacetimeDB procedure 写入 `profile_dashboard_state.wallet_balance``profile_wallet_ledger`。流水来源为 `new_user_registration_reward`,流水 ID 固定为 `new-user-registration:{user_id}`,重复调用不重复发放。 新注册用户默认获得 `10`点,注册链路通过 SpacetimeDB procedure 写入 `profile_dashboard_state.wallet_balance``profile_wallet_ledger`。流水来源为 `new_user_registration_reward`,流水 ID 固定为 `new-user-registration:{user_id}`,重复调用不重复发放。
注册赠送、邀请码奖励、充值、兑换码、资产扣费等都属于真实平台钱包流水。用户只要已经存在非 `snapshot_sync` 钱包流水,后续 `runtime_snapshot.game_state.playerCurrency` 不再覆盖 `wallet_balance`,只继续刷新游玩时长和玩过世界,避免首次保存旧运行态货币字段时把注册赠送覆盖成 `0` 注册赠送、邀请码奖励、充值、兑换码、资产扣费等都属于真实平台钱包流水。用户只要已经存在非 `snapshot_sync` 钱包流水,后续 `runtime_snapshot.game_state.playerCurrency` 不再覆盖 `wallet_balance`,只继续刷新游玩时长和玩过世界,避免首次保存旧运行态货币字段时把注册赠送覆盖成 `0`

View File

@@ -2,9 +2,9 @@
## 1. 范围 ## 1. 范围
本方案用于改造 `生成抓大鹅草稿` 的首版生成链路:点击按钮后先进入独立生成过程页,生成结束后自动进入抓大鹅草稿页,并在草稿`3D素材` Tab 预览本次生成的 3D 模型 本方案用于改造 `生成抓大鹅草稿` 的首版生成链路:点击按钮后先进入独立生成过程页,生成结束后自动进入抓大鹅结果页,并在结果`素材配置 > 物品` 预览本次生成的 2D 多视角物品素材
本次只把任意难度都收敛为 `3` 件物品。后续难度曲线恢复时,再把物品数、网格数和手动 3D 任务数量从配置中放开 草稿生成不再调用 Hyper3D Rodin也不再生成 GLB 模型。物品素材继续沿用原来的“生成图片 -> 网格拆分 -> 上传 OSS -> 写回草稿”机制,但每个物品必须生成 `5` 个不同视角的 2D 视图。试玩和正式运行态的消除次数、总物品数和物品种类数以结果页 `难度配置` 保存的难度为准。难度对应物品种类固定为:轻松 `3` 种、标准 `9` 种、进阶 `15` 种、硬核 `21` 种。历史硬核草稿若仍保存 `clearCount = 20`,运行态按新硬核升为 `21` 次消除、`63` 件总物品。正式发布前如果已生成 `image_ready` 且具备至少 `5` 张有效 `imageViews[]` 的物品种类不足当前难度要求,必须阻断发布;试玩不阻断,但启动时把物品种类自动降到当前可用 2D 素材数量
## 2. 前端流程 ## 2. 前端流程
@@ -20,34 +20,38 @@
生成页步骤固定为: 生成页步骤固定为:
```text ```text
生成游戏名称 -> 生成物品名称 -> 生成素材图 -> 切割独立图片 -> 上传图片资产 -> 生成3D模型 -> 写入草稿页 建立草稿存档 -> 生成作品计划 -> 生成背景提示词 -> 分批生成素材图 -> 切割独立图片 -> 上传图片资产 -> 校验素材结构 -> 生成背景音乐 -> 生成UI背景与容器 -> 写入草稿页
``` ```
生成页只展示题材和物品数量,不展示玩法规则说明。 生成页只展示题材和物品数量,不展示玩法规则说明。
当前 `match3d-generating` 进度页不是后端 task 状态订阅页,而是一个覆盖 `match3d_compile_draft` 长 action 的本地时间进度页:前端每 500ms 以本地时间刷新阶段展示,真正的生成完成仍以 action 返回为准。为避免长 action 未返回时页面完全无感,生成页在 `match3d_compile_draft` 执行期间每 3 秒旁路读取一次 session 和 work detail并用 profile 中已写回的 `generatedItemAssets` 更新 `生成3D模型` 的完成数量。Hyper3D 控制台中看到 3 个 Rodin 任务已经 `Done` 后,页面仍可能继续停留在 `生成3D模型`,此时通常表示后端还在等待下载列表、下载 GLB、转存 OSS 或写回 `generated_item_assets_json``generatedItemAssets` 已出现 `model_ready`,前端应逐步显示完成数量。排查时应看 api-server 日志中的 `抓大鹅 Rodin 状态轮询返回``抓大鹅 Rodin 下载列表轮询返回``抓大鹅 Rodin GLB 下载完成``抓大鹅 Rodin GLB 转存 OSS 完成` 当前 `match3d-generating` 进度页不是后端 task 状态订阅页,而是一个覆盖 `match3d_compile_draft` 长 action 的本地时间进度页:前端每 500ms 以本地时间刷新阶段展示,真正的生成完成仍以 action 返回为准。为避免长 action 未返回时页面完全无感,生成页在 `match3d_compile_draft` 执行期间每 3 秒旁路读取一次 session 和 work detail并用 profile 中已写回的 `generatedItemAssets` 更新图片素材完成数量。`generatedItemAssets` 已出现 `image_ready` 且带 `imageViews`,前端应逐步显示完成数量。
## 3. 后端编排边界 ## 3. 后端编排边界
外部模型和 OSS 上传全部由 `api-server` 编排,不进入 SpacetimeDB reducer。SpacetimeDB 继续只负责 Match3D 会话、草稿和作品 profile 的确定性写入。 外部生图、音频生成和 OSS 上传全部由 `api-server` 编排,不进入 SpacetimeDB reducer。SpacetimeDB 继续只负责 Match3D 会话、草稿和作品 profile 的确定性写入。
`match3d_compile_draft` action 的后端顺序为: `match3d_compile_draft` action 的后端顺序为:
1. 读取 session config。 1. 读取 session config。
2. 本次 MVP 的 `clearCount` 固定为 `3`,并同步用于草稿编译 2. 本次 `match3d_compile_draft` 生成动作按 `sessionId + profileId + action 时间戳` 构造幂等流水并预扣 `10` 泥点。余额不足时不继续创建草稿;后续任一步失败时自动按同额退款
3. 先调用 SpacetimeDB compile procedure 写入草稿。首次执行使用新 `profileId`;重试时复用 session draft / work profile 中已有 `profileId`。这一步不能等待 LLM、图片、OSS 或 Rodin 成功后才执行 3. 草稿编译先创建可恢复 profile素材生成数量由入口页难度派生的物品种类决定轻松 `3` 种、标准 `9` 种、进阶 `15` 种、硬核 `21`
4. 基于入口页题材设定文本调用文本模型生成作品元信息。模型固定请求 `gpt-4o`,只返回 JSON其中 `gameName` 为 4 到 12 个中文字符的游戏名称,`tags` 为 3 到 6 个中文短标签;`summary` 首版必须保持空字符串,结果页 `作品描述` 默认留给用户填写。文本模型不可用时保留第 3 步的本地兜底,不阻断草稿 4. 先调用 SpacetimeDB compile procedure 写入草稿。首次执行使用新 `profileId`;重试时复用 session draft / work profile 中已有 `profileId`。这一步不能等待 LLM、图片、音频或 OSS 成功后才执行
5. 调用文本模型生成 `3` 个题材下的短物品名称 5. 基于入口页题材设定文本调用文本模型生成作品生成计划。模型固定请求 `gpt-4o`,只返回 JSON其中 `gameName` 为 4 到 12 个中文字符的游戏名称,`summary` 为 18 到 48 个中文字符的作品描述。生成计划还必须包含 `tags``backgroundMusic.title``backgroundMusic.style``backgroundMusic.prompt``backgroundPrompt`,以及 `items[]` 中每个物品的 `name``soundPrompt``backgroundMusic.title` 是背景音乐名称,`backgroundMusic.prompt` 固定为空字符串,用于后续 Suno 纯音乐生成;`backgroundPrompt` 用于生成局内竖屏纯背景图只描述题材氛围、色彩和环境不得描述锅、圆盘、托盘、拼图槽、物品槽、HUD、UI、文字、按钮、倒计时、分数或物品。文本模型不可用时保留第 4 步的本地兜底,不阻断草稿
6. 调用项目当前图片链路 VectorEngine `gpt-image-2-all` 生成一张 `1:1` 素材图,提示词必须合入入口页选择的 `assetStylePrompt`。历史 `nanobanana2` 图片选项当前按项目统一决策回落到 VectorEngine不重新接入 APIMart 图片网关 6. 后端把生成计划中的 `gameName``summary` 写入 `match3d_work_profile` 作品信息后,自动调用作品标签生成器。标签生成器使用题材、作品名称和作品描述生成 3 到 6 个中文短标签;若调用失败或返回不足,则使用生成计划 tags 和本地兜底标签补齐。结果页手动 `AI生成作品标签` 也使用同一接口,并传入当前作品描述
7. 将素材图按 `n*n` 网格切割成独立图片。当前 `3` 件物品使用 `2*2` 网格,取前 `3` 7. 后端从同一份作品生成计划读取当前难度所需数量的短物品名称和音效提示词;不得再只生成物品名称而丢失后续音效生成上下文
8. 将素材图和每张独立图片上传到 OSS其中独立图片作为草稿页素材预览和 Rodin 图模型参考图;每次获得可恢复的图片资产后,都要回写 `match3d_work_profile.generated_item_assets_json` 8. 调用 APIMart `nanobanana2` / Gemini模型生成 `1:1``1K` 素材图,请求模型固定为 `gemini-3.1-flash-image-preview`,走 `POST {APIMART_BASE_URL}/images/generations`,并携带 `official_fallback = true`。提示词必须合入入口页选择的 `assetStylePrompt`,并强制每格使用统一纯绿色绿幕背景,避免白底或纹理背景进入运行态素材。该调整只作用于抓大鹅物品素材 sheet封面、9:16 纯背景图和 1:1 容器 UI 图仍继续使用项目现有 VectorEngine `gpt-image-2-all` 链路
9. 使用每张独立图片作为参考图,并行调用 Hyper3D Rodin 图生模型;所有 3D 模型任务必须在同一阶段同时提交、同时轮询状态、同时下载并转存 OSS禁止逐个物品串行等待模型完成。每个任务按官方 `check-status_reset_v` / `download-results_reset_v` 文档轮询状态和下载:状态查询使用 `subscription_key`,整体完成态以 `jobs[]` 聚合为准;下载查询使用生成响应顶层 `uuid` 作为 `task_uuid`,不能使用 `jobs.uuids` 子任务 uuid。只有 `jobs` 全部进入 `Done` 才能视为任务完成,任一 job `Failed` 则失败。完成后选择 `.glb` 下载文件,并把 GLB 转存到 OSS。Rodin 的 `subscriptionKey` 是上游 opaque token不做 256 字符这类短文本长度限制。Rodin 任务状态进入完成态后,下载列表仍可能延迟发布;后端必须对下载列表继续轮询,并兼容 `url``downloadUrl``fileUrl``signedUrl` 等下载字段别名,只有预览图而没有模型文件时不能伪装成 GLB 成功 9. 每个物品固定需要 `5` 个不同视角。单张素材图固定为 `5*5 = 25` 格,因此单张图承载 `5` 个物品。若用户要求或难度派生的物品种类不是 `5` 的倍数,后端必须向上补齐物品名称和对应图片到最近的 `5` 的倍数;例如标准难度需要 `9` 种玩法物品,实际生成 `10` 个物品名称和对应五视角图片。若草稿物品数超过 `5`,后端按每批 `5` 个物品自动分批,多张素材图并行生成
10. Rodin 每批完成后继续回写 `generated_item_assets_json`。成功素材状态为 `model_ready`;失败素材保留图片引用并记录 `error`,下次 `match3d_compile_draft` 只继续缺失模型的素材,不重复生成已完成的 GLB 10. 将每张素材图按固定 `5 行 * 5 列` 切割成独立图片,并按物品顺序连续分配 `5` 张视角图。素材图提示词必须要求 `5*5` 严格均匀排布、每格主体完整居中、统一纯绿色绿幕背景、相邻物体主体至少保留 `1/4` 单格宽度空白间距、不得跨格、贴边或越界,避免裁剪后相邻格内容污染。切割前必须先在整张素材图上把绿幕背景处理为透明 alpha再在每个理论格子内按透明背景/前景像素做内容边界校准,并带少量安全留白导出;不能做固定内缩裁剪,避免贴近格线但未跨格的樱桃、叶片、把手等主体边缘被切掉。每个物品 JSON 写入 `imageViews[]`,同时把第一个视角兼容写入 `imageSrc/imageObjectKey`
11. 在 HTTP 返回的 draft/profile DTO 中附带本次生成的素材资产预览信息;后续重进草稿页时从 work profile 的持久化 `generatedItemAssets` 恢复同一批素材 11. 将素材图和每张独立视角图片上传到 OSS。每次获得可恢复的图片资产后都要回写 `match3d_work_profile.generated_item_assets_json`。成功素材状态为 `image_ready`;失败素材保留已成功图片引用并记录 `error`。每个素材 JSON 同步保存 `soundPrompt`,首个素材 JSON 同步保存 `backgroundMusicTitle``backgroundMusicStyle``backgroundMusicPrompt` 保存为空字符串作为兼容字段
12. 后端在图片素材生成后使用 `backgroundMusic.title` 提交 Suno 背景音乐任务,`prompt` 为空,`tags` 来自 `backgroundMusic.style`,并固定走纯音乐生成。轮询完成后通过通用创作音频资产链路转存 OSS、确认 `asset_object`、绑定到 `match3d_work/background_music`,再写回首个素材的 `backgroundMusic`。自动草稿阶段必须拿到非空 `backgroundMusic.audioSrc` 才能返回成功曲名为空、Suno 提交/轮询失败、音频下载失败、OSS 转存失败或资产绑定失败时,本次 `match3d_compile_draft` 返回失败并停留在生成页,不能进入结果页后显示“暂无音乐”。
13. 草稿生成阶段不生成点击音效,只保存 `generatedItemAssets[].soundPrompt`;点击音效由结果页 `素材配置 > 物品` 详情面板手动生成并写回对应素材。
14. UI 背景生成由 `api-server` 调用 VectorEngine `gpt-image-2-all` 分成两张资产:第一张是 `9:16` 纯背景图不传锅参考图且必须禁止锅、圆盘、托盘、拼图槽、物品槽、HUD、文字、按钮、倒计时、分数和物品第二张是 `1:1` 题材容器 UI 图,固定传入 `public/match3d-background-references/pot-fused-reference.png` 作为参考图,只生成一个贴合题材设定的圆形或浅盘状竞技容器,不生成整页背景、文字、按钮或物品。容器图必须沿用参考图的大尺寸轻俯视构图:外轮廓接近画布四边,宽度约占 `86%-92%`、高度约占 `82%-90%`,内口为横向椭圆,禁止生成小容器、正俯视圆盘、侧视碗、餐盘或小托盘。纯背景上传到 `generated-match3d-assets/{sessionId}/{profileId}/background/{taskId}/background.png`,容器 UI 图上传到 `generated-match3d-assets/{sessionId}/{profileId}/ui-container/{taskId}/container.png`,两者都作为 `backgroundAsset` 挂在首个 `generatedItemAssets[]` JSON 上HTTP DTO 同时顶层输出兼容的 `backgroundPrompt``backgroundImageSrc``backgroundImageObjectKey``generatedBackgroundAsset`,容器图通过 `generatedBackgroundAsset.containerImageSrc/containerImageObjectKey` 返回。若作品尚无用户自定义封面,草稿生成完成后默认把容器 UI 图写入 `coverImageSrc`,作为草稿架和作品信息的默认封面。
15. 在 HTTP 返回的 draft/profile DTO 中附带本次生成的素材资产预览信息、背景音乐资产信息、背景资产信息和默认封面;后续重进草稿页时从 work profile 的持久化 `generatedItemAssets``coverImageSrc` 恢复同一批素材、音乐、UI 与封面。
若文本模型不可用或返回无法解析,后端必须降级为 `{themeText}抓大鹅` 与本地标签兜底,不阻断素材生成;但描述仍保持空字符串 若文本模型不可用或返回无法解析,后端必须降级为 `{themeText}抓大鹅`、本地作品描述与本地标签兜底,不阻断素材生成;标签仍通过作品标签生成器优先生成,失败后再用兜底标签补齐
草稿生成阶段调用 Hyper3D Rodin 并等待 GLB 下载完成;前端 `match3d_compile_draft` action 请求超时必须覆盖该长耗时链路,当前 Match3D client 使用 20 分钟超时。Rodin 单模型状态轮询预算为 10 分钟,下载列表发布轮询预算为 5 分钟GLB 下载和 OSS PutObject 各自设置 3 分钟 HTTP 超时,避免上游下载或转存连接长期悬挂。由于 3 个模型并行生成,总耗时按最慢模型计算,不能按模型数量线性叠加。结果页 `3D素材` Tab 直接加载已生成模型;用户点击 `重新生成` 时再复用 Rodin 安全代理,首版重新生成只更新当前页面内预览状态,后续正式资产绑定以独立技术方案为准 草稿生成阶段不再调用 Hyper3D Rodin,不生成 GLB也不等待任何模型轮询。前端 `match3d_compile_draft` action 的长耗时主要来自文本生成、分批 1K 生图、切图、OSS 上传、纯背景图、容器 UI 图和可选音频生成。批量新增物品由 `POST /api/creation/match3d/works/{profileId}/item-assets` 复用同一套 2D 素材图生成、固定 `5*5` 切图、OSS 上传和可选点击音效链路;若本次新增数量不是 `5` 的倍数,同样向上补齐名称和图片到最近的 `5` 的倍数。整图生成完成后立即丢弃补齐用临时物品,只对用户实际新增项执行绿幕抠背景、切割和上传,并只把这些真实新增项的 `imageViews[]` 写回 `generatedItemAssets`
## 4. 图片提示词 ## 4. 图片提示词
@@ -55,27 +59,41 @@
```text ```text
生成一张1:1图片 生成一张1:1图片
生成2*2网格素材图 生成严格5*5均匀网格素材图
整体画风遵循:... 整体画风遵循:...
只绘制这些物品:... 只绘制这些物品:...
不要出现文字、水印、UI、边框 每格背景必须是统一纯绿色绿幕背景,方便后续转透明
物品本身不得使用与绿幕相同的纯绿色
每格主体完整居中,禁止跨格、贴边或越界影响裁剪后的效果
相邻物体主体之间至少保留 1/4 单格宽度空白间距,物体主体不得占满格子
不要出现文字、水印、UI、边框、网格线、白色背景、灰色背景、纹理背景
``` ```
`包含若干个物品名称` 在落地中解释为“按生成出的物品名称绘制对应主体”,不要求图片上写出物品名称。这样可以避免文字渲染污染切图和后续手动 3D 模型参考 `包含若干个物品名称` 在落地中解释为“按生成出的物品名称绘制对应主体”,不要求图片上写出物品名称。这样可以避免文字渲染污染切图和局内 2D 素材表现
入口页内置风格参考图通过同一 VectorEngine `gpt-image-2-all` 能力生成,保存路径固定为: 内置 `像素复古` 不能只写“复古像素”或“有限色板”。入口页、参考图脚本和后端素材图 prompt 必须使用同一组硬约束:真正复古像素 2D 游戏道具 sprite先按约 `64x64` 低分辨率像素块绘制再整数倍放大,硬边方块像素清晰可见,有限色板 `12-24` 色;同时在负向约束中禁止抗锯齿、柔焦、平滑渐变、真实 3D 渲染、PBR 材质、摄影光照和平滑插画。后端即使只收到 `assetStyleId = pixel-retro``assetStyleLabel = 像素复古`,也必须补齐这组约束,避免旧会话、恢复会话或批量新增物品退回普通插画风格。
入口页内置 2D 风格参考图通过同一 VectorEngine `gpt-image-2-all` 能力生成,执行命令为 `npm run assets:match3d-style-references -- --live`。每张入口参考图只展示 `1` 个完整独立物品,不能展示 `5` 个物品样张或多物品散点图,避免风格选择被误读为物品数量配置。保存路径固定为:
```text ```text
public/match3d-style-references/clay-toy.png public/match3d-style-references/flat-icon.png
public/match3d-style-references/low-poly.png public/match3d-style-references/cel-cartoon.png
public/match3d-style-references/toy-plastic.png public/match3d-style-references/pixel-retro.png
public/match3d-style-references/wood-carved.png public/match3d-style-references/watercolor.png
public/match3d-style-references/voxel-block.png public/match3d-style-references/sticker-outline.png
public/match3d-style-references/metal-mecha.png public/match3d-style-references/painterly-icon.png
``` ```
这些图片只作为入口页风格选择的视觉参考,不进入用户草稿资产,不替代生成时的物品素材图。 这些图片只作为入口页风格选择的视觉参考,不进入用户草稿资产,不替代生成时的物品素材图。
局内容器 UI 图生成固定参考图路径为:
```text
public/match3d-background-references/pot-fused-reference.png
```
这张图只作为容器 UI 图的 VectorEngine `image` 参考输入,用来锁定“大尺寸轻俯视浅盘容器”的构图。参考图本身是 `1:1` 透明底容器素材,外轮廓接近画布四边,内口为横向椭圆;结果页没有真实生成容器时也只把它作为容器预览兜底,不能再作为 `9:16` 背景预览。每次草稿生成仍会根据 `backgroundPrompt` 生成新的题材化纯背景图;纯背景图不再传入该参考图,也不得生成锅或 UI 元素。
## 5. OSS 路径 ## 5. OSS 路径
新增 generated legacy prefix 新增 generated legacy prefix
@@ -88,47 +106,58 @@ generated-match3d-assets
```text ```text
generated-match3d-assets/{sessionId}/{profileId}/material-sheet/{taskId}/sheet.png generated-match3d-assets/{sessionId}/{profileId}/material-sheet/{taskId}/sheet.png
generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/image/image.png generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/views/view-01.png
generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/model/{taskUuid}/model.glb generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/views/view-02.png
generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/views/view-03.png
generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/views/view-04.png
generated-match3d-assets/{sessionId}/{profileId}/items/{itemSlug}/views/view-05.png
generated-match3d-assets/{sessionId}/{profileId}/background/{taskId}/background.png
``` ```
`itemSlug` 必须带 `itemId` 前缀,例如 `match3d-item-1-item`。中文物品名清洗后可能都退回 `item`,不能只用物品名做路径,否则多张切割图会写到同一个 object key导致草稿页预览图全部一致。 `itemSlug` 必须带 `itemId` 前缀,例如 `match3d-item-1-item`。中文物品名清洗后可能都退回 `item`,不能只用物品名做路径,否则多张切割图会写到同一个 object key导致草稿页预览图全部一致。
HTTP DTO 同时返回 `imageSrc``imageObjectKey``modelSrc``modelObjectKey``modelFileName``taskUuid``subscriptionKey``status`模型生成成功后 `status = model_ready`若后续允许部分模型失败降级,失败素材必须带 `error`,且不能伪装成可预览模型。前端模型预览必须通过 `/api/assets/read-bytes` 读取私有 GLB 字节并转成 Blob URL 后交给 Three.js不直接请求裸 `/generated-match3d-assets/...` 路径 HTTP DTO 同时返回兼容字段 `imageSrc``imageObjectKey`,以及正式 2D 字段 `imageViews[]``backgroundAsset``status`图片素材生成成功后 `status = image_ready`纯背景和容器 UI 图都生成成功后首个素材的 `backgroundAsset.status = image_ready`,并携带 `containerImageSrc/containerImageObjectKey`。前端通过 `/api/assets/read-url` 将 generated legacy path 换签后加载私有图片,不直接请求裸 `/generated-match3d-assets/...` 路径。运行态背景图和容器 UI 图同样通过 `/api/assets/read-url` 换签后加载:背景作为全屏 `object-cover`,容器作为中心棋盘覆盖层
## 5.1 运行态模型消费 ## 5.1 运行态 2D 素材消费
生成模型不仅用于结果页预览,也必须进入游戏运行态。运行态入口的传递链路为: 生成的 2D 五视角素材不仅用于结果页预览,也必须进入游戏运行态。运行态入口的传递链路为:
```text ```text
Match3DWorkProfile / PlatformMatch3DGalleryCard Match3DWorkProfile / PlatformMatch3DGalleryCard
-> Match3DRuntimeShell(generatedItemAssets) -> Match3DRuntimeShell(generatedItemAssets, backgroundImageSrc)
-> Match3DPhysicsBoard / Match3DTrayPreviewBoard -> Match3DPhysicsBoard / Match3DTrayPreviewBoard
``` ```
`Match3DPhysicsBoard``Match3DTrayPreviewBoard` 按运行快照中的 `itemTypeId` 稳定排序后,把生成出的模型顺序映射到对应类型。当前 MVP 固定 `clearCount = 3`,因此 `match3d-type-01/02/03` 分别对应生成列表的第 `1/2/3` 个模型;后续恢复更多物品生成时,后端必须继续保证 `generatedItemAssets` 顺序与类型编号一致 运行态按运行快照中的 `itemTypeId` 稳定排序后,把 `generatedItemAssets` 顺序映射到对应类型。加载某个物品实例时,从该类型素材的 `imageViews[]` 中按实例 id 稳定随机选择一个视角;若历史数据没有 `imageViews[]`,则回退到 `imageSrc/imageObjectKey`。没有生成图片或图片加载失败时,继续使用默认积木图标兜底
运行态背景优先读取 `backgroundImageSrc` / `generatedBackgroundAsset.imageSrc`,为空时从 `generatedItemAssets[].backgroundAsset.imageSrc/imageObjectKey` 兜底。中心容器优先读取 `generatedItemAssets[].backgroundAsset.containerImageSrc/containerImageObjectKey`;为空时继续使用默认圆形容器样式。运行态入口判断是否需要补读作品详情时,只能把 `imageViews[]``imageSrc/imageObjectKey` 视为“已有物品图片素材”;`backgroundMusic.audioSrc``clickSound.audioSrc``backgroundAsset.image*``backgroundAsset.containerImage*` 是随物品素材一起传入的附属运行态资产,不能单独证明物品素材已完整。也不能继续只用历史 `modelSrc/modelObjectKey` 判断,否则新 2D 草稿会在试玩或推荐流中被当成“无素材”并回退默认积木。`Match3DRuntimeShell` 只保留顶部返回、倒计时、重开三个控件;这些顶部控件和底部备选栏统一使用题材无关的半透明玻璃组件样式,不能随背景题材改成木质、金属、果园、科幻等主题皮肤,也不能重新烘进 AI 背景图。进度、组数、版本等状态信息不得再作为顶部常驻 UI 出现,避免遮挡生成背景和中心容器。
前端加载规则: 前端加载规则:
1. 优先读取 `modelSrc`为空时使用 `modelObjectKey` 1. 优先读取 `imageViews[]` 中的 `imageSrc/imageObjectKey`为空时使用兼容字段 `imageSrc/imageObjectKey`
2. 通过 `readAssetBytes` 调用 `/api/assets/read-bytes`,由同源后端读取 OSS 私有对象字节 2. 对 generated legacy path 通过同源 `/api/assets/read-url` 换签后交给浏览器图片加载;结果页 `素材配置 > 背景音乐``素材配置 > 物品` 的音频试听控件也必须先换签,不能把裸 `/generated-match3d-assets/...` 音频路径直接交给 `<audio>`
3. 使用 Three.js `GLTFLoader.parseAsync` 解析 GLB 字节,并按物品类型缓存模板 3. 场内物品、点击命中和备选栏继续使用后端快照中的 `itemInstanceId/itemTypeId/x/y/radius/layer`;生成 2D 图片只替换视觉表现,不承接规则真相
4. 场内每个物品和备选栏预览都从模板 clone 独立对象,点击命中继续写入 `itemInstanceId` 4. 同一物品类型的多个实例可以展示不同视角,但同一实例在本局中应稳定使用同一个视角,避免移动或入槽时闪图
5. 物理碰撞和边界仍沿用现有 `visualKey` 的程序化几何,生成 GLB 只替换视觉模型,不承接规则真相 5. 图片缺失、读取失败或解码失败时,继续使用默认积木素材,不能阻断开局、点击、入槽或结算
6. 模型缺失、读取失败或 WebGL 回退时,继续使用默认积木素材,不能阻断开局、点击、入槽或结算;调试模式下需要输出加载失败的 `itemTypeId`、模型来源和错误信息便于区分“资产没有传入”和“GLB 字节读取或解析失败”。
结果页点击 `试玩` 时,前端必须把当前结果页可见的 `generatedItemAssets` 带入运行态启动入参。`PUT /api/runtime/match3d/works/{profileId}` 若因为并发或旧快照返回了缺少素材的 profile`Match3DResultView` 需要把当前 draft / profile 的素材重新合并到运行态 profile并在启动试玩前调用生成素材保存接口把当前可见的 `generatedItemAssets` 写回作品 profile不能只在内存里把素材补到 `onStartTestRun(profile)`。发布同理必须先落库当前素材,再调用 `publish_match3d_work`,否则公开推荐流和正式运行态只能读到旧 profile 快照,历史草稿尤其容易表现为结果页有 3D 模型、正式游戏仍是默认积木。若历史草稿同时存在旧 `draft.generatedItemAssets` 和较新的 `profile.generatedItemAssets`,同 `itemId` 下以 profile 中已有的 `modelSrc` / `modelObjectKey` 补齐 draft不能让旧 draft 把模型状态覆盖回 `image_ready``PlatformEntryFlowShellImpl` 在渲染 `match3d-runtime` 时按 `run.profileId` 优先使用当前 `match3dProfile.generatedItemAssets`,只有 profileId 不匹配时才读取 `selectedPublicWorkDetail.generatedItemAssets`。推荐流内嵌正式运行态也必须走同一解析器;当推荐卡片摘要缺少素材时,启动前补读 `getMatch3DWorkDetail(profileId)`,把详情里的生成模型写入 `match3dProfile` 后再传给运行态。这样可以避免从公开详情页残留状态或推荐卡片旧摘要进入试玩 / 正式游戏时,把已生成草稿的 3D 模型覆盖成空列表。 结果页点击 `试玩` 时,前端必须把当前结果页可见的 `generatedItemAssets` 带入运行态启动入参。`PUT /api/runtime/match3d/works/{profileId}` 若因为并发或旧快照返回了缺少素材的 profile`Match3DResultView` 需要把当前 draft / profile 的素材重新合并到运行态 profile并在启动试玩前调用生成素材保存接口把当前可见的 `generatedItemAssets` 写回作品 profile不能只在内存里把素材补到 `onStartTestRun(profile)`。发布同理必须先落库当前素材,再调用 `publish_match3d_work`,否则公开推荐流和正式运行态只能读到旧 profile 快照。结果页顶部返回按钮固定回到平台创作页,不再回到抓大鹅专属内嵌入口表单;需要修改题材时由用户在创作页重新选择或从草稿继续进入。若历史草稿同时存在旧 `draft.generatedItemAssets` 和较新的 `profile.generatedItemAssets`,同 `itemId` 下以 profile 中已有的 `imageViews[]``imageSrc``imageObjectKey``backgroundMusic``backgroundAsset` 补齐 draft不能让旧 draft 把素材覆盖成空列表`PlatformEntryFlowShellImpl` 在渲染 `match3d-runtime` 时按 `run.profileId` 优先使用当前 `match3dRuntimeProfile / match3dProfile.generatedItemAssets`,只有 profileId 不匹配时才读取 `selectedPublicWorkDetail.generatedItemAssets`;即使当前 profile 暂时没有物品图片,也不能把同 profile 的已有 `generatedItemAssets` 覆盖为空数组。推荐流内嵌正式运行态也必须走同一解析器;当推荐卡片摘要缺少物品图片素材时,启动前补读 `getMatch3DWorkDetail(profileId)`,把详情里的生成图片、背景音乐和 UI 素材写入 `match3dRuntimeProfile` 后再传给运行态。这样可以避免从公开详情页残留状态或推荐卡片旧摘要进入试玩 / 正式游戏时,把已生成草稿的 2D 素材、音乐或 UI 覆盖成空列表。
2026-05-14 补充:`backgroundMusic` 虽然暂存在 `generatedItemAssets[]` 中,但语义上是作品级音乐。前端读取、保存、试玩、推荐流和运行态入口都必须先通过统一归一化逻辑把任意素材上的 `backgroundMusic/backgroundMusicTitle/backgroundMusicStyle/backgroundMusicPrompt` 迁移到首个素材,并清空其它素材上的作品级音乐字段,避免 `素材配置 > 背景音乐` 只读首项时显示“暂无音乐”,也避免 action response 中缺音乐的 draft assets 覆盖 work detail 中已经持久化的音乐。`match3d_compile_draft` action 完成后,如果同时拿到 `response.session.draft.generatedItemAssets``getMatch3DWorkDetail(profileId).item.generatedItemAssets`,必须以同 `itemId` 合并保留详情里的背景音乐、UI 背景和点击音效,再进入结果页或试玩。
历史草稿若仍保存 `status = model_ready``modelSrc``modelObjectKey`,仅作为旧版本兼容读取,不再参与新素材生产。历史外部模型链接转存接口只用于清理旧数据,不能被新草稿生成、批量新增或结果页普通编辑入口调用。
生成完成后自动进入试玩依赖 `selectionStageRef.current === 'match3d-generating'` 的同步判断。执行 `match3d_compile_draft` 前切到生成页时,必须同时写 `selectionStageRef.current = 'match3d-generating'``setSelectionStage('match3d-generating')`;只调用 React state 会让 action 很快返回时读到旧 stage表现为生成页已经 100% 但不进入试玩或结果页。拼图、大鱼吃小鱼、方洞挑战等同类生成页也遵循同一规则。
## 6. 自动保存与草稿恢复 ## 6. 自动保存与草稿恢复
点击 `生成抓大鹅草稿` 后,草稿存档创建与素材生成解耦: 点击 `生成抓大鹅草稿` 后,草稿存档创建与素材生成解耦:
1. 首次 compile 必须先写 `match3d_work_profile` 草稿行即使后续卡在文本模型、图片生成、OSS 上传、Rodin 生成或下载转存任意阶段。 1. 首次 compile 必须先写 `match3d_work_profile` 草稿行,即使后续卡在文本模型、图片生成、音频生成或 OSS 上传任意阶段。
2. 失败态前端要重新读取 session / work detail并刷新草稿作品架保证用户离开生成页后仍能在草稿 Tab 找到这份作品。 2. 失败态前端要重新读取 session / work detail并刷新草稿作品架保证用户离开生成页后仍能在草稿 Tab 找到这份作品。
3. 重新生成时优先使用当前 session 的 `draft.profileId``publishedProfileId`,不得重新创建 session后端读取同一 profile 的 `generated_item_assets_json` 后,只补齐缺失图片或缺失模型的阶段。 3. 重新生成时优先使用当前 session 的 `draft.profileId``publishedProfileId`,不得重新创建 session后端读取同一 profile 的 `generated_item_assets_json` 后,只补齐缺失图片或缺失音频的阶段。
4. 已有 `status = model_ready` 且带 `modelSrc` / `modelObjectKey` 的素材视为完成,不再重复调用 Rodin 4. 已有 `status = image_ready` 且带 `imageViews[]` `imageSrc/imageObjectKey` 的素材视为完成,不再重复生成图片
抓大鹅结果页的基础信息自动保存继续调用 `PUT /api/runtime/match3d/works/{profileId}` 更新名称、题材、描述、标签、封面、消除数和难度;该保存不得清空 `generated_item_assets_json`。结果页 `3D素材` Tab 手动点击 `重新生成` 并拿到 GLB 下载文件后,必须把当前素材草稿重新序列化成 `generatedItemAssets` 并写回作品 profile否则页面内预览会显示新模型,但试玩、发布和重进草稿会读取旧的空模型快照。SpacetimeDB `update_match3d_work` / `publish_match3d_work` 必须保留当前行的生成素材 JSON。 抓大鹅结果页的基础信息自动保存继续调用 `PUT /api/runtime/match3d/works/{profileId}` 更新名称、题材、描述、标签、封面、消除数和难度;该保存不得清空 `generated_item_assets_json`。结果页 `素材配置 > 物品` 只在独立面板中预览和编辑当前素材,不再提供单项重新生成入口;删除单项或批量新增成功后,必须把当前素材列表重新序列化成 `generatedItemAssets` 并写回作品 profile否则试玩、发布和重进草稿会读取旧素材快照。SpacetimeDB `update_match3d_work` / `publish_match3d_work` 必须保留当前行的生成素材 JSON。
草稿架重进路径为: 草稿架重进路径为:
@@ -136,22 +165,58 @@ Match3DWorkProfile / PlatformMatch3DGalleryCard
草稿 Tab -> getMatch3DWorkDetail(profileId) -> Match3DResultView(profile.generatedItemAssets) 草稿 Tab -> getMatch3DWorkDetail(profileId) -> Match3DResultView(profile.generatedItemAssets)
``` ```
因此 `map_match3d_work_summary_response` / `map_match3d_work_profile_response` 需要从 work profile snapshot 反序列化 `generated_item_assets_json` 并输出 `generatedItemAssets`。前端 `Match3DResultView` 的读取顺序为:有 `draft.generatedItemAssets` 时先用 draft 保留本次生成顺序和图片;同 `itemId``profile.generatedItemAssets` 中已有模型字段时,用 profile 模型字段补齐 draft从草稿架重进没有 draft 时,用 `profile.generatedItemAssets`;两者都没有才回退到默认 3D 素材占位 若草稿卡已经带有前端生成中标记,即使作品列表已经刷新成真实 `match3d_work_profile` 草稿行,点击该卡也必须优先回到 `match3d-generating` 生成过程页,并按 `sourceSessionId` 重新读取当前 session不能因为 `getSession` 返回了带 `draft` 的快照就直接进入结果页。若后台生成已经收口为 ready 且草稿卡仍有未读红点,首次点击必须消费红点并直接启动抓大鹅试玩,返回后展示 `Match3DResultView`;红点已读后的后续点击才按常规结果页恢复路径进入 `Match3DResultView`。因此点击恢复优先级固定为:未读 ready 红点自动试玩 > 仍在 generating 的本地 / 后台任务回生成页 > 普通草稿结果页
因此 `map_match3d_work_summary_response` / `map_match3d_work_profile_response` 需要从 work profile snapshot 反序列化 `generated_item_assets_json` 并输出 `generatedItemAssets` 与顶层背景字段。前端 `Match3DResultView` 的读取顺序为:有 `draft.generatedItemAssets` 时先用 draft 保留本次生成顺序和图片;同 `itemId``profile.generatedItemAssets` 中已有 `imageViews[]``imageSrc/imageObjectKey` 时,用 profile 图片字段补齐 draft背景资产同样必须从 profile 或 draft 的首个 `backgroundAsset` 保留到保存 payload从草稿架重进没有 draft 时,用 `profile.generatedItemAssets`;两者都没有才回退到默认素材占位。
结果页 `作品信息` Tab 字段命名对齐拼图草稿: 结果页 `作品信息` Tab 字段命名对齐拼图草稿:
1. `作品名称` 对应 Match3D `gameName` 1. `作品名称` 对应 Match3D `gameName`
2. `作品描述` 对应 Match3D `summary`,草稿生成默认空 2. `作品描述` 对应 Match3D `summary`,草稿生成阶段由同一次作品生成计划自动填入
3. `作品标签` 对应 Match3D `tags`可由 AI 首次生成并允许用户继续编辑 3. `作品标签` 对应 Match3D `tags`草稿生成阶段在写入名称和描述后自动调用标签生成器填入;结果页仍允许用户继续编辑或再次 AI 生成
4. 封面图与作品名称不再拆成左右两个大模块;封面只作为同一 Tab 内的可选上传入口,避免和作品基础信息割裂。 4. 封面图与作品名称不再拆成左右两个大模块;封面只作为同一 Tab 内的可选入口,避免和作品基础信息割裂。草稿生成默认使用生成出的中心容器 UI 图作为 `coverImageSrc`。点击封面图必须弹出独立编辑面板,不允许在当前作品信息面板下方展开。封面面板布局参考拼图创作页上传卡:移动端优先、左侧/上方为方形预览,右侧/下方为提示词与操作区。面板支持三类输入:本地上传图片、上传后开启 AI 重绘、直接引用 `物品素材``UI素材` 中已有图片作为封面或 AI 重绘参考图。AI 重绘通过 `api-server` 的 Match3D 作品封面生成接口调用 VectorEngine `gpt-image-2-all`,生成结果转存到 `generated-match3d-assets/{sessionId}/{profileId}/cover/{taskId}/cover.png` 后再写回 `coverImageSrc`;关闭 AI 重绘时只把选中的 Data URL 或 generated legacy path 写入封面字段。
`3D素材` 详情页只保留 结果页 `难度配置` Tab 取代旧 `玩法配置`,不再展示旧的分散输入项。该 Tab 顶部使用横向离散拖动条调整难度,四个刻度分别为 `轻松 / 标准 / 进阶 / 硬核`;拖动条只能落在这四个点上,刻度标签可点击切换。该 Tab 必须与创作入口页使用同一组难度选项,并统一把原“类型素材图片 / 局内类型”等口径归一为 `物品种类`
1. 模型预览区:优先加载 `modelSrc` 对应 GLB缺失时加载 `modelObjectKey`,支持拖动旋转;没有模型时展示空预览。 | 难度 | clearCount | difficulty | 总物品数 | 物品种类 |
| ---- | ---------: | ---------: | -------: | -------: |
| 轻松 | 8 | 2 | 24 | 3 |
| 标准 | 12 | 4 | 36 | 9 |
| 进阶 | 16 | 6 | 48 | 15 |
| 硬核 | 21 | 8 | 63 | 21 |
预览区展示 `需要消除``总物品数``物品种类``已生成物品种类`。历史草稿如果保存的是旧 `clearCount/difficulty`,前端按 `clearCount` 精确命中优先、否则按 `difficulty` 就近归一到上述选项,并把归一后的数值保存回 profile。发布校验以 `generatedItemAssets[]``image_ready` 且至少有 `5` 张有效 `imageViews[]` 的素材数量为准;试玩启动时用同一数量计算 `itemTypeCountOverride`,不足时自动降低,不修改草稿难度配置本身。历史单图 `imageSrc/imageObjectKey` 只作为运行态和预览兜底,不计入新发布素材完成数。
结果页 `素材配置` Tab 取代旧一级素材入口,并包含三个子 Tab
1. `物品`:显示 2D 物品素材列表、五视角预览、素材名称、点击音效提示词和点击音效生成入口。
2. `UI`:预览生成的竖屏游戏纯背景图和中心容器 UI 图。背景读取顺序为 draft 顶层背景、draft `generatedBackgroundAsset`、profile 顶层背景、profile `generatedBackgroundAsset``generatedItemAssets[].backgroundAsset`、本地兜底图;容器读取 `generatedItemAssets[].backgroundAsset.containerImageSrc/containerImageObjectKey`,缺失时使用默认圆形容器。该页必须展示默认画面描述提示词,默认值来自草稿生成计划的 `backgroundPrompt` 或持久化 `backgroundAsset.prompt`;用户修改后点击重新生成,后端同时生成纯背景图和容器 UI 图,并把新的 `backgroundAsset` 写回同一份 `generated_item_assets_json`。UI 子 Tab 还必须提供独立的运行态 UI 预览面板,直接用当前纯背景图、容器 UI 图、顶部返回/倒计时/重开控件和底部默认托盘模拟竖屏页面,不在 Tab 下方内联展开。
3. `背景音乐`:承载原一级音乐 Tab 的背景音乐曲名、风格、生成进度和试听控件;背景音乐始终按纯音乐生成,前端不提供提示词输入。
旧一级 `音乐` Tab 删除;抓大鹅背景音乐入口只保留在 `素材配置 > 背景音乐`
`素材配置 > 物品` 详情页只保留:
1. 五视角预览区:优先展示 `imageViews[]`,缺失时展示兼容字段 `imageSrc/imageObjectKey`
2. 素材名称输入。 2. 素材名称输入。
3. `重新生成` 按钮 3. 可编辑的点击音效提示词输入
4. 点击音效生成入口。
详情页不再展示参考图、用途、提示词、文生/图生切换、状态查询、下载列表、taskUuid 或 subscriptionKey。 详情页不再展示参考图、用途、模型提示词、文生/图生切换、状态查询、下载列表、taskUuid 或 subscriptionKey。
`物品素材` 列表项点击必须弹出独立预览面板,不允许在列表右侧或列表下方内联展示。列表本身使用移动端至少两列的多列卡片布局;每个列表项只展示图片预览、物品名称和垃圾箱删除图标,不展示用途、状态胶囊、视角数量或 `2D素材` 标记。预览面板只承担查看五视角图片、编辑素材名称、编辑点击音效提示词和生成点击音效;不再展示 `重新生成` 按钮。列表项自身支持单项删除,删除后立即把剩余 `generatedItemAssets` 写回作品 profile。批量新增通过列表顶部按钮打开独立面板面板内每个输入框只输入一个物品名称`新增物品名称` 按钮追加一个输入框;提交后按输入框顺序清洗、去重并调用 Match3D 作品批量生图接口。生成进度同时显示在批量新增面板和 `素材配置 > 物品` 列表顶部面板可关闭后台生成继续推进不阻塞封面、音频等其他生成操作。后端复用草稿生成的素材图、切图、OSS 上传和可选点击音效流程,但仅按实际可新增名称持久化,不重新生成已有物品,不新增 SpacetimeDB 表,最终仍写回同一份 `generated_item_assets_json`。批量新增先补齐到 `5` 个参与整图生成,随后丢弃补齐用临时物品,只对真实新增物品抠背景、切割和上传。批量新增计费按实际可新增名称每 `5` 个消耗 `2` 泥点,不足 `5` 个向上取整;重复名称、已有名称和超过容量上限的名称不计费。
## 6.1 音频生成与扣费
抓大鹅结果页音频生成复用通用创作音频路由:
1. `素材配置 > 背景音乐` 默认读取首个 `generatedItemAssets[0].backgroundMusicTitle/backgroundMusicStyle`,用户可继续编辑曲名和风格;`backgroundMusicPrompt` 保留为空字符串兼容旧 JSON生成请求固定传空 `prompt`
2. 物品点击音效默认读取对应 `generatedItemAssets[].soundPrompt`,用户可在 `素材配置 > 物品` 详情面板内编辑。
3. 背景音乐与物品音效生成过程必须显示进度条;提交任务、等待生成、转存资产和完成分别推进到不同进度,不再只展示旋转图标。
4. 音频生成完成后立即展示浏览器原生 audio 控件,支持试听。
5. `POST /api/creation/audio/background-music/{task_id}/asset``POST /api/creation/audio/sound-effect/{task_id}/asset` 在真正拿到音频并转存资产前,由后端按 `taskId + 资产槽位` 幂等预扣;背景音乐扣 `5` 泥点,物品点击音效扣 `10` 泥点。任务仍在处理中时不扣费。资产下载、OSS 转存或资产绑定失败时后端自动退款。前端只展示生成按钮和进度,不自行计算或写入钱包。
创作入口不展示 `生成音效` Toggle。草稿生成阶段不产生物品点击音效任务也不产生点击音效相关扣费入口只产生一次固定 `10` 泥点的草稿生成扣费。结果页 `素材配置 > UI` 重新生成背景固定扣 `2` 泥点。物品点击音效由结果页 `素材配置 > 物品` 详情面板手动触发,每个音效按单独任务和单独 `match3d_click_sound` 资产槽位扣费。音效生成失败不影响草稿,失败素材保留 `soundPrompt`,用户可在结果页物品详情面板手动重试。
## 7. 验收 ## 7. 验收
@@ -173,4 +238,4 @@ cargo check -p spacetime-client --manifest-path server-rs\Cargo.toml
cargo check -p spacetime-module --manifest-path server-rs\Cargo.toml cargo check -p spacetime-module --manifest-path server-rs\Cargo.toml
``` ```
真实草稿生成需要本地私密环境配置 `VECTOR_ENGINE_API_KEY``HYPER3D_API_KEY` 和 OSS 访问变量。后端改动后使用 `npm run api-server` 启动,并检查 `/healthz` 真实草稿生成需要本地私密环境配置 `APIMART_BASE_URL` / `APIMART_API_KEY` / `APIMART_IMAGE_REQUEST_TIMEOUT_MS` 用于物品素材 sheet配置 `VECTOR_ENGINE_BASE_URL` / `VECTOR_ENGINE_API_KEY` 用于封面、背景和容器 UI并补齐完整 `ALIYUN_OSS_BUCKET``ALIYUN_OSS_ENDPOINT``ALIYUN_OSS_ACCESS_KEY_ID``ALIYUN_OSS_ACCESS_KEY_SECRET`。如果只配置 bucket 和 endpoint抓大鹅素材、封面或背景生成会在调用外部生图前返回 `OSS 未完成环境变量配置``details.missingEnv` 会列出缺少的 AccessKey 项;不要回退到 Rodin/GLB 或伪造本地上传成功。开启音频生成还需要对应音频上游配置。后端改动后使用 `npm run api-server` 启动,并检查 `/healthz`

View File

@@ -2,9 +2,13 @@
> 2026-05-08 更新:抓大鹅创作端入口已重新开放,当前 `match3d.visible` 为 `true`。本文件记录 F1 接入能力,入口是否展示以 `NEW_WORK_ENTRY_CONFIG_2026-05-01.md` 和 `src/config/newWorkEntryConfig.ts` 为准。 > 2026-05-08 更新:抓大鹅创作端入口已重新开放,当前 `match3d.visible` 为 `true`。本文件记录 F1 接入能力,入口是否展示以 `NEW_WORK_ENTRY_CONFIG_2026-05-01.md` 和 `src/config/newWorkEntryConfig.ts` 为准。
> >
> 2026-05-10 更新:抓大鹅入口页对齐拼图入口页,直接嵌入创作页模板 Tab。入口表单不再展示参考图、消除次数输入、难度数值滑杆和题材/物品/难度摘要框,仅保留题材主题大输入框和难度选项。难度选项负责派生 `clearCount` 与 `difficulty`,生成按钮必须展示 `消耗20光点` > 2026-05-10 更新:抓大鹅入口页对齐拼图入口页,直接嵌入创作页模板 Tab。入口表单不再展示参考图、消除次数输入、难度数值滑杆和题材/物品/难度摘要框,仅保留题材主题大输入框和难度选项。难度选项负责派生 `clearCount` 与 `difficulty`。
> >
> 2026-05-10 补充:入口页新增 `3D素材风格` 横向滑动选择,首批风格参考图通过 VectorEngine `gpt-image-2-all` 生成并保存到 `public/match3d-style-references/`。最后一个选项为 `自定义`,点击后弹出独立面板填写画风描述。 > 2026-05-12 补充:入口页风格选择收敛为 `2D素材风格`,首批常见 2D 素材风格参考图通过 `npm run assets:match3d-style-references -- --live` 调用 VectorEngine `gpt-image-2-all` 生成并保存到 `public/match3d-style-references/`。2026-05-13 起,入口参考图固定只展示 `1` 个完整独立物品,不再展示 `5` 个物品样张或多物品散点图。最后一个选项为 `自定义`,点击后弹出独立面板填写画风描述。
>
> 2026-05-13 补充:草稿素材实际生成数量按 `5` 的倍数向上补齐,补齐物品同样需要生成名称和五视角图片。素材图提示词固定要求 `5*5` 严格均匀排布,禁止主体跨格、贴边或越界影响裁剪效果。
>
> 2026-05-13 补充:创作页隐藏抓大鹅 `生成音效` Toggle草稿生成固定预扣 `10` 泥点,按钮展示 `消耗10泥点`。点击音效生成只保留在结果页 `素材配置 > 物品` 详情面板中手动触发。
## 1. 阶段边界 ## 1. 阶段边界
@@ -43,7 +47,7 @@ badge: 可创建
表单只展示三个输入块: 表单只展示三个输入块:
1. `想做一个什么题材的抓大鹅?`:大文本输入框,收集 `themeText` 1. `想做一个什么题材的抓大鹅?`:大文本输入框,收集 `themeText`
2. `3D素材风格`:横向滑动风格卡,选择会写入 `assetStyleId``assetStyleLabel``assetStylePrompt` 2. `2D素材风格`:横向滑动风格卡,选择会写入 `assetStyleId``assetStyleLabel``assetStylePrompt`
3. `难度`:四个选项按钮,选项内部派生消除次数和难度数值。 3. `难度`:四个选项按钮,选项内部派生消除次数和难度数值。
当前难度映射固定为: 当前难度映射固定为:
@@ -52,7 +56,7 @@ badge: 可创建
轻松 -> clearCount 8, difficulty 2 轻松 -> clearCount 8, difficulty 2
标准 -> clearCount 12, difficulty 4 标准 -> clearCount 12, difficulty 4
进阶 -> clearCount 16, difficulty 6 进阶 -> clearCount 16, difficulty 6
硬核 -> clearCount 20, difficulty 8 硬核 -> clearCount 21, difficulty 8
``` ```
入口页不再上传参考图,提交 payload 中 `referenceImageSrc` 固定为 `null`。如果从旧会话或旧草稿恢复,前端只根据已有 `difficulty` 选择最接近的难度选项,并按当前选项重新派生 `clearCount``difficulty` 入口页不再上传参考图,提交 payload 中 `referenceImageSrc` 固定为 `null`。如果从旧会话或旧草稿恢复,前端只根据已有 `difficulty` 选择最接近的难度选项,并按当前选项重新派生 `clearCount``difficulty`
@@ -60,12 +64,12 @@ badge: 可创建
内置风格选项为: 内置风格选项为:
```text ```text
黏土手作 / 低多边形 / 玩具塑料 / 木质雕刻 / 体素积木 / 金属机甲 / 自定义 扁平图标 / 赛璐璐卡通 / 像素复古 / 手绘水彩 / 贴纸描边 / 厚涂图标 / 自定义
``` ```
自定义风格必须在弹出面板中填写描述后才能应用。入口表单必须在移动端创作页可视区内完成题材、风格、难度和生成按钮的展示,页面自身不产生纵向滚动;风格卡只允许横向滑动。 自定义风格必须在弹出面板中填写描述后才能应用。入口表单必须在移动端创作页可视区内完成题材、风格、难度和生成按钮的展示,页面自身不产生纵向滚动;风格卡只允许横向滑动。
生成按钮文案为 `生成抓大鹅草稿`,按钮内必须同时展示 `消耗20光点`。UI 中不默认展示玩法规则长文,也不展示隐藏派生数值的摘要框。 生成按钮文案为 `生成抓大鹅草稿`,按钮内必须同时展示 `消耗10泥点`。UI 中不默认展示玩法规则长文,也不展示隐藏派生数值的摘要框。
## 5. mock client ## 5. mock client
@@ -111,7 +115,7 @@ POST /api/creation/match3d/sessions/:sessionId/compile
2. 切换到 `抓大鹅` Tab 后,页面内直接显示抓大鹅入口表单,不提前创建会话。 2. 切换到 `抓大鹅` Tab 后,页面内直接显示抓大鹅入口表单,不提前创建会话。
3. 表单不展示参考图、`需要消除次数``难度数值``题材``物品``难度`摘要框。 3. 表单不展示参考图、`需要消除次数``难度数值``题材``物品``难度`摘要框。
4. 输入题材、选择风格和难度后,提交 payload 包含派生后的 `clearCount``difficulty``referenceImageSrc``null`,并包含 `assetStyleId``assetStyleLabel``assetStylePrompt` 4. 输入题材、选择风格和难度后,提交 payload 包含派生后的 `clearCount``difficulty``referenceImageSrc``null`,并包含 `assetStyleId``assetStyleLabel``assetStylePrompt`
5. 生成按钮展示 `消耗20光点` 5. 生成按钮展示 `消耗10泥点`,创作页不展示 `生成音效` Toggle
6. 点击 `自定义` 风格弹出独立面板,填写后应用到提交 payload未填写时不能应用空自定义风格。 6. 点击 `自定义` 风格弹出独立面板,填写后应用到提交 payload未填写时不能应用空自定义风格。
7. 移动端创作页内抓大鹅入口内容不产生纵向滚动,风格卡横向滑动。 7. 移动端创作页内抓大鹅入口内容不产生纵向滚动,风格卡横向滑动。
8. 点击生成后创建会话并进入草稿生成/结果页链路。 8. 点击生成后创建会话并进入草稿生成/结果页链路。

View File

@@ -275,6 +275,12 @@ type Match3DAutoSaveState = 'idle' | 'saving' | 'saved' | 'error';
F2 不实现运行态本身;只冻结结果页如何发起试玩。 F2 不实现运行态本身;只冻结结果页如何发起试玩。
### 12.1 生成完成自动试玩补充2026-05-12
抓大鹅表单生成草稿完成后,如果用户仍停留在 `match3d-generating` 进度页,前端应立即用刚生成的 `Match3DWorkProfile` 启动试玩,并把运行态返回目标设置为 `match3d-result`。试玩过程中点击左上角返回时,进入同一份抓大鹅草稿结果页查看与编辑。
该自动试玩只响应当前等待中的生成页;如果用户已经返回草稿 Tab 或切到其它页面,后台生成完成只更新草稿可见状态,不主动切屏。自动启动失败时,仍保留结果页草稿作为兜底入口。
--- ---
## 13. 发布接口 ## 13. 发布接口

View File

@@ -6,33 +6,33 @@
本轮在“我的”页面的“会员充值”入口落地账户充值弹窗,包含两个页签: 本轮在“我的”页面的“会员充值”入口落地账户充值弹窗,包含两个页签:
1. `点充值` 1. `点充值`
2. `会员卡充值` 2. `会员卡充值`
前端只负责展示与发起购买,套餐、价格、赠送规则、会员权益、生效时间、钱包余额与交易流水统一由 `server-rs` 后端返回。当前没有真实支付网关,本轮采用服务端模拟支付成功:创建订单后立即写入余额或会员状态,并返回最新账户中心快照。后续接入真实支付时,只替换订单支付状态推进,不改前端套餐与账户快照 contract 前端只负责展示与发起购买,套餐、价格、赠送规则、会员权益、生效时间、钱包余额与交易流水统一由 `server-rs` 后端返回。普通 H5 / 本地联调继续使用 `mock` 渠道:创建订单后立即写入余额或会员状态,并返回最新账户中心快照。微信小程序 web-view 使用 `wechat_mp` 渠道:创建订单时只写入 `pending` 订单并返回小程序 `wx.requestPayment` 参数,真实到账以后端微信支付通知为准
## 2. 产品规则 ## 2. 产品规则
### 2.1 点充值套餐 ### 2.1 点充值套餐
| productId | 点 | 金额分 | 徽标 | 说明 | | productId | 点 | 金额分 | 徽标 | 说明 |
| --- | ---: | ---: | --- | --- | | ------------- | ---: | -----: | -------- | -------------- |
| `points_60` | 60 | 600 | 首充双倍 | 首充送60光点 | | `points_60` | 60 | 600 | 首充双倍 | 首充送60泥点 |
| `points_180` | 180 | 1800 | 首充双倍 | 首充送180光点 | | `points_180` | 180 | 1800 | 首充双倍 | 首充送180泥点 |
| `points_300` | 300 | 3000 | 首充双倍 | 首充送300光点 | | `points_300` | 300 | 3000 | 首充双倍 | 首充送300泥点 |
| `points_680` | 680 | 6800 | 首充双倍 | 首充送680光点 | | `points_680` | 680 | 6800 | 首充双倍 | 首充送680泥点 |
| `points_1280` | 1280 | 12800 | 首充双倍 | 首充送1280点 | | `points_1280` | 1280 | 12800 | 首充双倍 | 首充送1280点 |
| `points_3280` | 3280 | 32800 | 首充双倍 | 首充送3280点 | | `points_3280` | 3280 | 32800 | 首充双倍 | 首充送3280点 |
点充值固定为 `¥6 / ¥18 / ¥30 / ¥68 / ¥128 / ¥328` 六个档位。全部档位参与首充双倍:用户历史上没有 `points_recharge` 流水时,本次购买到账点为基础点与等额赠送点之和;已有充值流水后只到账基础点。实际到账点写入交易流水,余额以 SpacetimeDB projection 为准。 点充值固定为 `¥6 / ¥18 / ¥30 / ¥68 / ¥128 / ¥328` 六个档位。全部档位参与首充双倍:用户历史上没有 `points_recharge` 流水时,本次购买到账点为基础点与等额赠送点之和;已有充值流水后只到账基础点。实际到账点写入交易流水,余额以 SpacetimeDB projection 为准。
### 2.2 会员卡套餐 ### 2.2 会员卡套餐
| productId | 类型 | 天数 | 金额分 | 权益 | | productId | 类型 | 天数 | 金额分 | 权益 |
| --- | --- | ---: | ---: | --- | | --------------- | ---- | ---: | -----: | --------------------------------- |
| `member_month` | 月卡 | 30 | 2800 | 免点回合数100每日签到加成0% | | `member_month` | 月卡 | 30 | 2800 | 免点回合数100每日签到加成0% |
| `member_season` | 季卡 | 90 | 7800 | 免点回合数100每日签到加成100% | | `member_season` | 季卡 | 90 | 7800 | 免点回合数100每日签到加成100% |
| `member_year` | 年卡 | 365 | 24800 | 免点回合数100每日签到加成210% | | `member_year` | 年卡 | 365 | 24800 | 免点回合数100每日签到加成210% |
购买会员时,如果当前会员仍有效,则从当前到期时间顺延;如果已过期或从未购买,则从当前服务端时间开始计算。状态只区分 `普通` 与已生效会员,前端不自行推断。 购买会员时,如果当前会员仍有效,则从当前到期时间顺延;如果已过期或从未购买,则从当前服务端时间开始计算。状态只区分 `普通` 与已生效会员,前端不自行推断。
@@ -42,8 +42,8 @@
需要 Bearer JWT。返回 需要 Bearer JWT。返回
1. 当前点余额、会员状态、到期时间 1. 当前点余额、会员状态、到期时间
2. 点套餐与会员套餐 2. 点套餐与会员套餐
3. 会员权益表 3. 会员权益表
4. 最近订单摘要 4. 最近订单摘要
@@ -63,26 +63,65 @@
行为: 行为:
1. 校验 `productId` 1. 校验 `productId`
2. 后端创建已支付订单 2. `paymentChannel = "mock"`后端创建已支付订单
3. 光点套餐写入钱包余额与流水 3. `paymentChannel = "wechat_mp"` 时后端创建待支付订单,并调用微信支付 JSAPI 下单生成小程序支付参数
4. 会员套餐写入会员状态 4. mock 泥点套餐立即写入钱包余额与流水mock 会员套餐立即写入会员状态
5. 返回最新账户中心快照与订单摘要 5. wechat_mp 订单不提前发泥点或会员,只返回待支付订单、账户中心快照与 `wechatMiniProgramPayParams`
兼容路径:`POST /api/runtime/profile/recharge/orders` 兼容路径:`POST /api/runtime/profile/recharge/orders`
响应里的 `wechatMiniProgramPayParams` 只在微信小程序支付渠道返回,字段直接对应 `wx.requestPayment`
```json
{
"wechatMiniProgramPayParams": {
"timeStamp": "1777110165",
"nonceStr": "nonce",
"package": "prepay_id=wx201410272009395522657a690389285100",
"signType": "RSA",
"paySign": "..."
}
}
```
### 3.3 `POST /api/profile/recharge/wechat/notify`
微信支付通知地址,无需 Bearer JWT。行为
1. 真实渠道使用微信支付平台公钥和 `Wechatpay-*` 请求头验签。
2. 使用 `WECHAT_PAY_API_V3_KEY` 解密通知 `resource`
3. 仅当 `trade_state = "SUCCESS"` 时确认订单支付。
4. 使用微信通知里的 `out_trade_no` 查本地 `profile_recharge_order.order_id`,把订单从 `pending` 改为 `paid`
5. 将微信平台订单号写入 `provider_transaction_id`,用于对账、查单、退款和客服排障。
6. 在同一 SpacetimeDB procedure 内写入钱包流水或会员到期时间,确保重复通知幂等。
关键环境变量:
| 变量 | 说明 |
| ---------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `WECHAT_PAY_ENABLED` | 是否启用微信支付客户端 |
| `WECHAT_PAY_PROVIDER` | `mock``real` |
| `WECHAT_PAY_MCH_ID` | 微信支付商户号 |
| `WECHAT_PAY_MERCHANT_SERIAL_NO` | 商户 API 证书序列号,用于请求微信支付签名头 |
| `WECHAT_PAY_PRIVATE_KEY_PEM` / `WECHAT_PAY_PRIVATE_KEY_PATH` | 商户 API 私钥 |
| `WECHAT_PAY_PLATFORM_PUBLIC_KEY_PEM` / `WECHAT_PAY_PLATFORM_PUBLIC_KEY_PATH` | 微信支付平台公钥或平台证书公钥,用于回调验签 |
| `WECHAT_PAY_PLATFORM_SERIAL_NO` | 微信支付通知头里的平台证书/公钥序列号 |
| `WECHAT_PAY_API_V3_KEY` | 32 字节 API v3 密钥,用于解密通知资源 |
| `WECHAT_PAY_NOTIFY_URL` | 公网 HTTPS 通知地址,通常为 `/api/profile/recharge/wechat/notify` |
## 4. 前端交互 ## 4. 前端交互
1. “我的”页会员充值按钮打开独立弹窗,不在当前面板下方展开。 1. “我的”页会员充值按钮打开独立弹窗,不在当前面板下方展开。
2. 弹窗顶部标题为 `账户充值`,右上角关闭。 2. 弹窗顶部标题为 `账户充值`,右上角关闭。
3. 默认打开 `点充值`,可切换到 `会员卡充值` 3. 默认打开 `点充值`,可切换到 `会员卡充值`
4. 点击套餐后调用下单接口,按钮进入处理中状态,成功后刷新 `profileDashboard` 4. 点击套餐后调用下单接口,按钮进入处理中状态;小程序环境走 native 支付页拉起 `wx.requestPayment`,支付页返回后刷新 `profileDashboard`
5. 弹窗内不写大段说明文案,只保留必要金额、点、会员权益和状态反馈。 5. 弹窗内不写大段说明文案,只保留必要金额、点、会员权益和状态反馈。
6. 会员卡充值区以套餐卡片优先展示周期、价格和处理状态;移动端单列,桌面端三列,权益表允许横向滚动,避免小屏挤压。 6. 会员卡充值区以套餐卡片优先展示周期、价格和处理状态;移动端单列,桌面端三列,权益表允许横向滚动,避免小屏挤压。
## 5. 验收 ## 5. 验收
1. 普通用户打开弹窗能看到点与会员套餐。 1. 普通用户打开弹窗能看到点与会员套餐。
2. 点购买后余额增加,流水来源为 `points_recharge` 2. 点购买后余额增加,流水来源为 `points_recharge`
3. 首充赠送只在首次点充值时生效。 3. 首充赠送只在首次点充值时生效。
4. 会员购买后会员状态与到期时间立即更新。 4. 会员购买后会员状态与到期时间立即更新。
5. 移动端弹窗单列可滚动,桌面端接近参考图卡片网格。 5. 移动端弹窗单列可滚动,桌面端接近参考图卡片网格。

View File

@@ -13,9 +13,9 @@
## 2. 前端交互 ## 2. 前端交互
### 2.1 百梦号复制 ### 2.1 陶泥号复制
1. 点击“我的”页百梦号后的复制按钮后,按钮文案临时切换为 `已复制` 1. 点击“我的”页陶泥号后的复制按钮后,按钮文案临时切换为 `已复制`
2. 复制失败时临时切换为 `复制失败` 2. 复制失败时临时切换为 `复制失败`
3. 状态自动恢复为 `复制` 3. 状态自动恢复为 `复制`
@@ -84,7 +84,7 @@ SpacetimeDB 正式表 `user_account` 需要增加 `avatar_url: Option<String>`
## 5. 验收 ## 5. 验收
1. 创作页已发布作品分享按钮点击后显示 `已复制` 1. 创作页已发布作品分享按钮点击后显示 `已复制`
2. “我的”页百梦号复制按钮点击后显示 `已复制` 2. “我的”页陶泥号复制按钮点击后显示 `已复制`
3. “我的”页不展示 `手机号``正常` 标签。 3. “我的”页不展示 `手机号``正常` 标签。
4. 昵称编辑成功后,资料卡与顶部账号入口同步新昵称。 4. 昵称编辑成功后,资料卡与顶部账号入口同步新昵称。
5. 昵称与头像裁剪弹窗面板不透明,不能露出底层页面内容。 5. 昵称与头像裁剪弹窗面板不透明,不能露出底层页面内容。

View File

@@ -7,14 +7,14 @@
在现有“我的”Tab 功能入口区(常用功能)落地三个轻量入口,入口顺序固定为 `邀请好友``填邀请码``玩家社区` 在现有“我的”Tab 功能入口区(常用功能)落地三个轻量入口,入口顺序固定为 `邀请好友``填邀请码``玩家社区`
1. `邀请好友`:弹出面板展示当前账号绑定的邀请码、邀请奖励规则和成功邀请用户列表。 1. `邀请好友`:弹出面板展示当前账号绑定的邀请码、邀请奖励规则和成功邀请用户列表。
2. `填邀请码`:弹出面板填写邀请码,成功后邀请者与被邀请者各获得 `30` 点。 2. `填邀请码`:弹出面板填写邀请码,成功后邀请者与被邀请者各获得 `30` 点。
3. `玩家社区`:弹出面板展示微信群与 QQ 群正式二维码图片。 3. `玩家社区`:弹出面板展示微信群与 QQ 群正式二维码图片。
## 后端边界 ## 后端边界
- 邀请码、邀请关系与奖励发放全部存入 `server-rs/crates/spacetime-module` - 邀请码、邀请关系与奖励发放全部存入 `server-rs/crates/spacetime-module`
- Axum 只做鉴权、参数转发与响应映射,不在 API 层自行计算奖励。 - Axum 只做鉴权、参数转发与响应映射,不在 API 层自行计算奖励。
- 前端只读取后端状态与调用提交接口,不做本地加点。 - 前端只读取后端状态与调用提交接口,不做本地加点。
- 钱包余额继续复用 `profile_dashboard_state.wallet_balance` - 钱包余额继续复用 `profile_dashboard_state.wallet_balance`
- 奖励流水继续复用 `profile_wallet_ledger`,新增来源类型: - 奖励流水继续复用 `profile_wallet_ledger`,新增来源类型:
- `invite_inviter_reward` - `invite_inviter_reward`
@@ -43,7 +43,7 @@
- 每个用户拥有一个稳定邀请码,首次进入邀请中心时自动生成。 - 每个用户拥有一个稳定邀请码,首次进入邀请中心时自动生成。
- 用户不能填写自己的邀请码。 - 用户不能填写自己的邀请码。
- 用户最多填写一个邀请码,成功后不可修改。 - 用户最多填写一个邀请码,成功后不可修改。
- 被邀请者绑定成功后获得 `30` 点。 - 被邀请者绑定成功后获得 `30` 点。
- 邀请者每天最多获得 `10` 次邀请奖励,超过后关系仍可绑定,被邀请者仍获得奖励,邀请者当次不再加分。 - 邀请者每天最多获得 `10` 次邀请奖励,超过后关系仍可绑定,被邀请者仍获得奖励,邀请者当次不再加分。
- 每次奖励都写入钱包流水,钱包余额以后端返回为准。 - 每次奖励都写入钱包流水,钱包余额以后端返回为准。
@@ -60,7 +60,7 @@
"invitedUsers": [ "invitedUsers": [
{ {
"userId": "user_001", "userId": "user_001",
"displayName": "百梦玩家", "displayName": "陶泥儿玩家",
"avatarUrl": null, "avatarUrl": null,
"boundAt": "2026-05-01T08:00:00Z" "boundAt": "2026-05-01T08:00:00Z"
} }
@@ -89,10 +89,10 @@
- `server-rs/crates/spacetime-module` 已新增邀请码与邀请关系表,邀请中心读取和填码绑定均通过 SpacetimeDB procedure 执行。 - `server-rs/crates/spacetime-module` 已新增邀请码与邀请关系表,邀请中心读取和填码绑定均通过 SpacetimeDB procedure 执行。
- `server-rs/crates/api-server` 已挂接 `/api/runtime/profile/referrals/*``/api/profile/referrals/*` 两组路由。 - `server-rs/crates/api-server` 已挂接 `/api/runtime/profile/referrals/*``/api/profile/referrals/*` 两组路由。
- 前端“我的”Tab 三个功能入口均打开独立弹窗,玩家社区使用 `media/social-media-group/wechat.png``media/social-media-group/qq.png` 两张正式二维码图片。 - 前端“我的”Tab 三个功能入口均打开独立弹窗,玩家社区使用 `media/social-media-group/wechat.png``media/social-media-group/qq.png` 两张正式二维码图片。
- 复制邀请会复制邀请码和邀请链接;填码成功后刷新个人看板点。 - 复制邀请会复制邀请码和邀请链接;填码成功后刷新个人看板点。
- 邀请好友弹窗展示 `邀请一个用户注册,双方都可获得 30 点。每日最多获得十次邀请奖励。`,不再展示“邀请 / 已奖 / 今日”三项统计。 - 邀请好友弹窗展示 `邀请一个用户注册,双方都可获得 30 点。每日最多获得十次邀请奖励。`,不再展示“邀请 / 已奖 / 今日”三项统计。
- 邀请好友弹窗底部展示成功邀请用户头像和昵称列表;没有成功邀请时展示短空状态。 - 邀请好友弹窗底部展示成功邀请用户头像和昵称列表;没有成功邀请时展示短空状态。
- “我的”页 `邀请好友` 按钮副标题展示 `双方得30点icon``玩家社区` 按钮副标题展示 `每日领福利` - “我的”页 `邀请好友` 按钮副标题展示 `双方得30点icon``玩家社区` 按钮副标题展示 `每日领福利`
- “我的”页功能入口区不展示 `常用功能` 标题和 `快捷入口` 副标题,避免首屏重复说明类文案。 - “我的”页功能入口区不展示 `常用功能` 标题和 `快捷入口` 副标题,避免首屏重复说明类文案。
## 前端交互 ## 前端交互

View File

@@ -9,6 +9,7 @@
1. 新建作品入口配置统一存放在 SpacetimeDB 的 `creation_entry_config` / `creation_entry_type_config` 表;默认种子位于 `server-rs/crates/spacetime-module/src/runtime/creation_entry_config.rs` 1. 新建作品入口配置统一存放在 SpacetimeDB 的 `creation_entry_config` / `creation_entry_type_config` 表;默认种子位于 `server-rs/crates/spacetime-module/src/runtime/creation_entry_config.rs`
2. `visible` 控制玩法是否展示在创作 Tab 模板入口、新建作品入口和创作类型弹层中。 2. `visible` 控制玩法是否展示在创作 Tab 模板入口、新建作品入口和创作类型弹层中。
3. `open` 控制玩法是否允许点击创建以及对应创作 / runtime API 路由是否放行;`open: false` 时入口保持展示但禁用,并由 `api-server` 熔断对应玩法 API。 3. `open` 控制玩法是否允许点击创建以及对应创作 / runtime API 路由是否放行;`open: false` 时入口保持展示但禁用,并由 `api-server` 熔断对应玩法 API。
- 前端作品架、发现页聚合和预加载只应请求 `open: true` 的玩法接口;`open: false` 的未开放玩法可以展示为敬请期待入口,但不得把对应 API 熔断错误透传到草稿页或发现页。
4. `title``subtitle``badge` 控制玩法卡片文案。 4. `title``subtitle``badge` 控制玩法卡片文案。
5. `startCard` 控制旧创作中心顶部新建作品模块的标题、辅助文案和移动端角标文案;当前创作 Tab 首屏标题固定在 `PlatformEntryFlowShellImpl.tsx`,不再由 `startCard` 控制。 5. `startCard` 控制旧创作中心顶部新建作品模块的标题、辅助文案和移动端角标文案;当前创作 Tab 首屏标题固定在 `PlatformEntryFlowShellImpl.tsx`,不再由 `startCard` 控制。
6. `typeModal` 控制平台创作类型弹层标题和描述。 6. `typeModal` 控制平台创作类型弹层标题和描述。
@@ -28,6 +29,21 @@
| AIRP | 是 | 否 | 保留入口,显示敬请期待 | | AIRP | 是 | 否 | 保留入口,显示敬请期待 |
| 视觉小说 | 是 | 否 | 保留入口,显示敬请期待,暂不允许创建视觉小说草稿 | | 视觉小说 | 是 | 否 | 保留入口,显示敬请期待,暂不允许创建视觉小说草稿 |
| 智能创作 | 否 | 是 | 入口隐藏,既有 `creative-agent` 链路保留 | | 智能创作 | 否 | 是 | 入口隐藏,既有 `creative-agent` 链路保留 |
| 宝贝识物 | 是 | 是 | 寓教于乐首关模板,必须由 `creation_entry_type_config` 默认种子或后台入口开关保持存在 |
## 排障约束
`baby-object-match` 是寓教于乐创作模板和发现页宝贝识物作品合流的共同开关。若 `creation_entry_type_config` 缺少该行,前端会同时出现“创作界面没有宝贝识物模板”和“寓教于乐分类下已发布作品消失”的现象。
默认种子必须包含:
- `id = baby-object-match`
- `title = 宝贝识物`
- `visible = true`
- `open = true`
- `sort_order = 90`
入口图首版复用 `/child-motion-demo/picture-book-grass-stage.png`,后续如生成专属 image-2 入口图,可通过后台入口开关更新 `imageSrc`
## 验收 ## 验收
@@ -36,5 +52,5 @@
3. 未开放玩法点击态保持禁用,不应进入鉴权或创建会话链路。 3. 未开放玩法点击态保持禁用,不应进入鉴权或创建会话链路。
4. 已开放玩法点击后必须进入对应创建链路;若用户未登录,先走登录保护。 4. 已开放玩法点击后必须进入对应创建链路;若用户未登录,先走登录保护。
5. 创作 Tab 首屏应显示“10分钟创作一个精品互动玩法”并默认展示拼图创作表单。 5. 创作 Tab 首屏应显示“10分钟创作一个精品互动玩法”并默认展示拼图创作表单。
6. 智能创作入口隐藏后不应出现“Hi, 朋友”“问一问百梦”或“一句话生成闪应用”等旧首页入口。 6. 智能创作入口隐藏后不应出现“Hi, 朋友”“问一问陶泥儿”或“一句话生成闪应用”等旧首页入口。
7. 方洞挑战入口隐藏后,不应出现在创作 Tab 模板入口、创作中心顶部卡带、平台创作类型弹层和创作页作品架中;既有 `SH-` 作品号、广场详情和试玩 runtime 链路不因此删除。 7. 方洞挑战入口隐藏后,不应出现在创作 Tab 模板入口、创作中心顶部卡带、平台创作类型弹层和创作页作品架中;既有 `SH-` 作品号、广场详情和试玩 runtime 链路不因此删除。

View File

@@ -1,6 +1,6 @@
# 密码登录入口历史落地设计 # 密码登录入口历史落地设计
> 2026-04-25 更新:当前产品策略已调整为“不开放密码注册”。新用户必须通过手机号验证码注册/登录,密码登录只面向已经登录后设置过密码的手机号账号。`POST /api/auth/entry` 只接受 `phone + password`,不支持邮箱、用户名或百梦号登录,也不承担自动建号能力。本文原有“密码自动建号”内容仅作为历史背景保留,当前落地以本更新和 [PASSWORD_LOGIN_CHANGE_RESET_DESIGN_2026-04-24.md](./PASSWORD_LOGIN_CHANGE_RESET_DESIGN_2026-04-24.md) 为准。 > 2026-04-25 更新:当前产品策略已调整为“不开放密码注册”。新用户必须通过手机号验证码注册/登录,密码登录只面向已经登录后设置过密码的手机号账号。`POST /api/auth/entry` 只接受 `phone + password`,不支持邮箱、用户名或陶泥号登录,也不承担自动建号能力。本文原有“密码自动建号”内容仅作为历史背景保留,当前落地以本更新和 [PASSWORD_LOGIN_CHANGE_RESET_DESIGN_2026-04-24.md](./PASSWORD_LOGIN_CHANGE_RESET_DESIGN_2026-04-24.md) 为准。
> >
> 2026-04-28 更新:为开发期本地/测试服联调新增服务端环境变量 `GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED`,默认 `false`。仅当该变量显式为 `true` 时,`POST /api/auth/entry` 可对未知手机号用本次密码直接创建账号并登录;默认关闭时仍严格保持未知手机号返回 `401` 的生产语义。该开关不得用于生产环境,也不新增任何前端规则说明文案。 > 2026-04-28 更新:为开发期本地/测试服联调新增服务端环境变量 `GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED`,默认 `false`。仅当该变量显式为 `true` 时,`POST /api/auth/entry` 可对未知手机号用本次密码直接创建账号并登录;默认关闭时仍严格保持未知手机号返回 `401` 的生产语义。该开关不得用于生产环境,也不新增任何前端规则说明文案。
@@ -17,7 +17,7 @@
1. `api-server` 对外只暴露 `phone + password` 的最小接口。 1. `api-server` 对外只暴露 `phone + password` 的最小接口。
2. `module-auth` 只负责已存在手机号账号的密码校验。 2. `module-auth` 只负责已存在手机号账号的密码校验。
3. 密码入口不创建账号,不接收邮箱、用户名或百梦号。 3. 密码入口不创建账号,不接收邮箱、用户名或陶泥号。
4. 登录成功后与 JWT、refresh cookie 的衔接方式。 4. 登录成功后与 JWT、refresh cookie 的衔接方式。
## 1.1 当前冻结结论 ## 1.1 当前冻结结论
@@ -239,7 +239,7 @@
1. 未知手机号密码登录返回 `401`,且不创建账号。 1. 未知手机号密码登录返回 `401`,且不创建账号。
2. 已登录手机号账号设置密码后可用 `phone + password` 登录。 2. 已登录手机号账号设置密码后可用 `phone + password` 登录。
3. 同手机号错误密码返回 `401` 3. 同手机号错误密码返回 `401`
4. 邮箱、用户名或百梦号作为密码登录标识返回 `400` 4. 邮箱、用户名或陶泥号作为密码登录标识返回 `400`
5. 登录成功时返回 access token。 5. 登录成功时返回 access token。
6. 登录成功时写回 refresh cookie。 6. 登录成功时写回 refresh cookie。
7. `GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED` 默认关闭时行为不变。 7. `GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED` 默认关闭时行为不变。

View File

@@ -19,7 +19,7 @@
沿用现有 `POST /api/auth/entry` 沿用现有 `POST /api/auth/entry`
1. 请求字段固定为 `phone``password`,前端只提交手机号。 1. 请求字段固定为 `phone``password`,前端只提交手机号。
2. 后端只按标准手机号归一化后查找账号,不兼容邮箱、用户名、百梦号或历史开发游客标识。 2. 后端只按标准手机号归一化后查找账号,不兼容邮箱、用户名、陶泥号或历史开发游客标识。
3. 手机号不存在时返回 `401`,不创建账号。 3. 手机号不存在时返回 `401`,不创建账号。
4. 手机号存在但未设置密码时返回 `401` 4. 手机号存在但未设置密码时返回 `401`
5. 校验成功后签发 access token并写入 refresh cookie。 5. 校验成功后签发 access token并写入 refresh cookie。
@@ -32,7 +32,8 @@
2. 请求字段:`currentPassword``newPassword` 2. 请求字段:`currentPassword``newPassword`
3. 若账号未设置过密码,允许 `currentPassword` 为空并设置首个密码。 3. 若账号未设置过密码,允许 `currentPassword` 为空并设置首个密码。
4. 若账号已有密码,必须校验 `currentPassword` 后才能写入 `newPassword` 4. 若账号已有密码,必须校验 `currentPassword` 后才能写入 `newPassword`
5. 修改成功后递增用户 `token_version`,使旧 access token 失效;前端沿用当前 refresh 会话刷新登录态 5. 修改成功后递增用户 `token_version`,使旧 access token 失效。
6. `2026-05-13` 起,修改密码成功后必须撤销该用户全部 active `refresh_session`,并在响应中清除当前 refresh cookie前端清空本地 access token 并回到未登录态。用户需要使用新密码重新登录。
### 2.3 重置密码 ### 2.3 重置密码
@@ -76,3 +77,16 @@
3. 只有用户显式修改或重置密码后,才允许密码登录。 3. 只有用户显式修改或重置密码后,才允许密码登录。
后续迁移到 SpacetimeDB 表时,保持同一语义:密码哈希字段允许为空,密码登录 reducer 不承担注册能力,验证码登录 reducer 承担“无账号则自动注册”的唯一注册入口。 后续迁移到 SpacetimeDB 表时,保持同一语义:密码哈希字段允许为空,密码登录 reducer 不承担注册能力,验证码登录 reducer 承担“无账号则自动注册”的唯一注册入口。
## 5. 2026-05-12 快照同步修复
重置密码和修改密码都会改变认证真相:`password_hash``password_login_enabled``token_version`,重置密码还会立即创建新的 refresh session修改密码还会撤销全部旧 refresh session。因此 API 层在 `POST /api/auth/password/change``POST /api/auth/password/reset` 成功后,必须和密码登录、手机号登录、刷新、退出一样调用 `sync_auth_store_snapshot_to_spacetime()`
若只更新本地 `InMemoryAuthStore` 而不同步 SpacetimeDB 认证快照,`api-server` 重启时可能从旧的 SpacetimeDB 表或旧快照恢复账号状态,表现为用户已通过忘记密码重设成功,但再次密码登录仍返回“手机号或密码错误”。启动恢复时应从 SpacetimeDB 表、SpacetimeDB 快照记录和本地 `GENARRATIVE_AUTH_STORE_PATH` 文件中选择可判断的最新快照;当本地文件更新且远端表无更新时间戳时,优先使用本地文件并尝试回写 SpacetimeDB避免旧远端状态覆盖刚重设的密码。
验证命令:
```bash
cargo test -p module-auth password --manifest-path server-rs/Cargo.toml
cargo test -p api-server password --manifest-path server-rs/Cargo.toml
```

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