Compare commits

..

3 Commits

Author SHA1 Message Date
suzmii ca53c30d01 共享记忆同步 #504 关闭口径:迁移归属与复核条件
- decision-log 2026-09-24 条目补充:#504 以 Reviewed/Won't Fix 关闭,跟踪交回迁移侧,复核与重新打开条件见 #504 关闭评论
- pitfalls 同条目处理口径补上 #504 关闭状态与重新打开路径
2026-09-24 12:18:34 +08:00
suzmii 771965ea40 记录 AGC 快照换号重传修复未落地:根因与迁移约束写入共享记忆,文档回退到现行状态
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m2s
Project CI / Backend tests (pull_request) Failing after 17s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m41s
Project CI / Frontend tests (pull_request) Successful in 2m18s
Project CI / Repository checks (pull_request) Failing after 13s
Project CI / AI game creator shell web tests (pull_request) Successful in 1m22s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 8m47s
Project CI / Native shell tests (pull_request) Successful in 6m21s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 9m8s
- decision-log 改写 2026-09-24 条目:只固化根因与「数据与 IO 往后端挪」必须保留的三条约束,注明客户端索引分桶实现保留在分支 fix/api-timeout(3be8e40bc)且 PR #505 已关闭
- decision-log 补充分层结论:本次改动只碰本地持久化格式与 native-only 诊断视图字段,未涉及客户端与服务端的路由、DTO、对象键与清单结构,即不涉及协议层
- pitfalls 同条目把处理口径改为暂缓落地,验证口径改为按分支状态描述
- 主规范索引描述回退为整份只保存一个账号基线、换号后冷启动全量对比,并指向 issue #504 与 decision-log
- 快照里程碑文档回退索引口径,验收项 13 标为随架构迁移重新定义
2026-09-24 12:05:10 +08:00
suzmii 3be8e40bc2 修复 AGC 换号后整项目快照重传导致的日志刷屏与客户端超时
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m20s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m57s
Project CI / Backend tests (pull_request) Successful in 4m52s
Project CI / Native shell tests (pull_request) Successful in 5m59s
Project CI / Frontend tests (pull_request) Successful in 1m56s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 8m46s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 9m0s
Project CI / AI game creator shell web tests (pull_request) Successful in 1m24s
Project CI / Repository checks (pull_request) Successful in 1m50s
- 项目快照索引升级为 schema v2:按账号分桶保存基线,换号不再让其它账号的基线失效,也不会被其它账号覆盖
- 同步只读取并写回当前登录账号的基线,其它账号的基线原样保留
- 读取时按 JSON 版本判定并迁移 v1 单账号索引到它自己记录的 userId 桶,格式升级不额外触发一次重传
- read_local_project_snapshot_state 增补 baselineCount / baselinePresent,fileCount / syncRevision / syncedAtMs 改为当前登录账号的基线口径
- 新增与改写用例:账号切换后基线互不覆盖、切回旧账号差异为空、v1 索引迁移进对应账号桶
- 同步更新快照主规范、快照里程碑文档、shared-memory decision-log 与 pitfalls
2026-09-24 11:20:39 +08:00
403 changed files with 19478 additions and 20444 deletions
@@ -5,42 +5,131 @@ description: Guide use of Genarrative's hosted external editor/canvas MCP or asy
# Genarrative External Editor API
Use Genarrative to manage canvas projects and asset-library records, generate images, character animations, videos, and audio, and edit images. Discover the hosted integration at `https://www.genarrative.world/api/external/v1/agent-integration.json`.
Discover the live integration through `GET https://www.genarrative.world/api/external/v1/agent-integration.json`. Treat `GET https://www.genarrative.world/api/external/v1/openapi.json` as the field-level source of truth. In this repository, the same contract is `docs/openapi/genarrative-external-v1.openapi.json`.
Connect to `https://www.genarrative.world/api/external/v1/mcp` using Streamable HTTP and a Bearer API Key. Read tool descriptions and input schemas from `tools/list`; read the documents below through `resources/read` when needed. The hosted service needs no local MCP server. For direct REST, use the live `/api/external/v1/openapi.json` contract (in this repository: `docs/openapi/genarrative-external-v1.openapi.json`).
Prefer the hosted Streamable HTTP MCP at `https://www.genarrative.world/api/external/v1/mcp` when the Agent supports remote MCP with a custom Bearer token. It exposes the External v1 operations as tools and the Skill documentation as resources; it does not require a local MCP server. Use this complete Skill package when remote MCP is unavailable or local-file upload needs client-side orchestration.
## Working with the Service
Prefer `scripts/genarrative_external_api.py` for runnable REST calls. It uses only Python stdlib, reads the local private API Key file, keeps the production base URL fixed, uploads local references, and wraps asynchronous submission, polling, and result retrieval.
- Select tools by the requested outcome. Use `find_canvas_projects` and `find_assets` to locate existing context; create projects or folders only when the task needs them. A folder need not have the same name as the project.
- For generation, specify project, library, and `canvasCompletion` fields only as supported by the selected tool and needed for the requested destination. Do not duplicate records already created by generation.
- Upload local references using `prepare_asset_upload`: request a ticket, transfer the file from the client, then confirm the object. Confirmation does not create a canvas layer or a project/library record. Use the reference type accepted by the target tool; some operations require a registered resource or asset ID rather than an object key.
- Generation is paid and asynchronous. Keep one stable `idempotencyKey` per logical generation and retain the returned `operationId`. Call `check_generation` according to `pollAfterMs`; consume `result` only after `completed`, and report the safe error on `failed`. A polling timeout does not justify another generation.
- Read actual artifacts and warnings before claiming the requested deliverable is complete. Use project/library reads for complete persisted records, and `find_assets` with `action=get_download_url` for temporary media access.
- Keep API Keys and temporary upload/download credentials out of chat, repository files, and logs. Business calls operate within the API Key's owner and scopes.
## Workflow
1. Discover the integration manifest. Choose hosted MCP when supported; otherwise use the helper or direct REST.
2. Before the first generation in a new conversation, obtain a canvas name unless an existing `projectId` and `assetFolderId` were supplied. Create or reuse a project and a same-name asset-library folder. Retain `canvasName`, `projectId`, `assetFolderId`, and the current art spec.
3. Normalize art requests into a reusable spec. Ask only for missing values that block the selected operation. Reuse the spec until the user changes its style, subject family, palette, format, or constraints.
4. Infer the operation from the user's intent. Do not ask the user to select an API unless two operations would produce materially different artifacts.
5. If a reference exists only as a local file, upload and confirm it first. Pass the stable returned `objectKey` to operations that accept object references; never substitute a temporary signed URL. For an icon-spritesheet primary spec, additionally create a project resource or asset record with `assetKind="icon-spec"`, then pass the returned resource or asset ID as `referenceId`.
6. For generation endpoints that support the fields, include `projectId`, `assetFolderId`, an asset label, and `canvasCompletion` so the result enters both the canvas and its same-name library folder.
7. Treat every generation POST as asynchronous. Send one stable `Idempotency-Key` per logical request, retain the returned `operationId`, and poll the returned `statusUrl` or `GET /api/external/v1/generations/{operationId}` according to `pollAfterMs`.
8. Consume `result` only after `status=completed`. On `failed`, surface the safe error. On a client timeout or lost response, retain the operation/key; do not create a replacement request.
9. Reload the normal project or asset-library read endpoint when the caller needs complete authoritative state. Generation results are intentionally compact.
10. Stay within `/api/external/v1`. Never call internal workers, queues, admin/profile APIs, or SpacetimeDB endpoints unless the user explicitly changes scope.
## Essential Invariants
- Authenticate MCP and business API calls with `Authorization: Bearer <tnr_sk_...>`. Never ask the user to paste a key into chat or place one in repository files.
- All nine generation POST routes require `Idempotency-Key` and return HTTP `202`; `202` is durable acceptance, not a media result.
- Retry an uncertain submission only with the exact same body and the same idempotency key. A polling timeout is not permission to generate again.
- Use stable references such as `objectKey`, project resource ID, or asset ID where each operation permits them. Image edit/redraw is stricter: `sourceReferenceId` accepts only a registered project resource ID or asset ID; upload confirmation alone is not enough. Use `/assets/read-url` only for temporary preview/download access.
- Preserve both warning channels after completion. A general `warning` can coexist with `sliceWarning`; do not discard either.
- Do not invent missing derivatives. A source-preserved warning means the main source remains usable but requested post-processing failed. A slice warning means the complete transparent sheet is usable but individual slices are absent.
- Icon spritesheet generation requires an explicit `sliceMode` and has no default. Use `sliceMode="grid"` with the `gridX` and `gridY` the requirement actually names (1-32 each) only for equal grid cells or fixed slots; use `sliceMode="connected-components"` for free-form sheets or an open number of subjects, and constrain the count with `sliceCount` instead of inventing grid dimensions. `connected-components` must not carry `gridX`/`gridY`; an omitted, contradictory, or misapplied declaration returns 400 before billing.
- For successful `style="pixelArt"`, treat completed-result and nested resource/asset dimensions as the final logical-grid PNG dimensions. They may differ from `size`, `imageSize`, the provider image, and `canvasCompletion.placeholder`; do not rescale or reject the artifact to match those inputs.
- Keep generated artifacts in the canvas and asset library together. Character animation accepts `assetFolderId` and `assetLabel`; its completed result directly returns the final `assetKind="character-animation"` resource and asset with formal sequence fields. Do not create a duplicate first-frame record.
## Documentation Navigation
Read the reference relevant to the current operation; exact input fields and enums come from the tool schema or OpenAPI.
Read only the references needed for the task, but always verify exact schemas and enums against live OpenAPI:
| Need | Reference | MCP resource URI |
| --- | --- | --- |
| Choose tools and actions by user intent | [Capability routing](references/capability-routing.md) | `genarrative://external-editor/skill/references/capability-routing.md` |
| Map tool calls to REST operations | [API operations](references/api-operations.md) | `genarrative://external-editor/skill/references/api-operations.md` |
| Configure credentials, upload files, handle retries and deletion | [Authentication and safety](references/authentication-and-safety.md) | `genarrative://external-editor/skill/references/authentication-and-safety.md` |
| Construct requests, poll results, place media, handle warnings | [Requests and outputs](references/requests-and-outputs.md) | `genarrative://external-editor/skill/references/requests-and-outputs.md` |
- `references/capability-routing.md`: read before selecting an MCP tool or REST operation, creating a canvas session, or working in the AI game creator visual DAG.
- `references/api-operations.md`: read when constructing project, canvas, asset-library, upload, generation, or generation-status calls.
- `references/authentication-and-safety.md`: read before handling credentials, local files, OSS form upload, retries, private media, or logs.
- `references/requests-and-outputs.md`: read before building generation payloads, polling, interpreting compact results, applying canvas completion, or handling post-processing warnings.
`genarrative://external-editor/usage` contains the short service instructions; `genarrative://external-editor/openapi` contains the REST contract. This entry is available at `genarrative://external-editor/skill`. Reading a resource does not install the downloadable Skill or its Python helper.
The hosted MCP exposes the same documents through:
## Direct REST and Local Helpers
- `genarrative://external-editor/skill`
- `genarrative://external-editor/skill/references/capability-routing.md`
- `genarrative://external-editor/skill/references/api-operations.md`
- `genarrative://external-editor/skill/references/authentication-and-safety.md`
- `genarrative://external-editor/skill/references/requests-and-outputs.md`
- `genarrative://external-editor/openapi`
When remote MCP is unavailable or local-file orchestration needs a helper, the complete package is available at `GET /api/external/v1/skill.zip`; the raw entry is at `GET /api/external/v1/skill/SKILL.md`. Verify the archive SHA-256 against the integration manifest before installing. The archive includes this entry, four references, `scripts/genarrative_external_api.py`, and `agents/openai.yaml`. Discovery and documentation downloads are public; MCP and business calls require authentication.
## Hosted Integration Discovery
The Python stdlib helper reads the private API Key file described in [authentication and safety](references/authentication-and-safety.md) and uses the production base URL. For a read-only smoke test:
- Manifest: `GET /api/external/v1/agent-integration.json`.
- Hosted MCP: `POST /api/external/v1/mcp`, Streamable HTTP, same Bearer API Key.
- OpenAPI: `GET /api/external/v1/openapi.json`.
- Raw Skill entry: `GET /api/external/v1/skill/SKILL.md`.
- Complete Skill archive: `GET /api/external/v1/skill.zip`.
The archive contains this main file, four one-level references, the Python helper, and `agents/openai.yaml`. Verify its SHA-256 against `agent-integration.json` before installing. Discovery, OpenAPI, and Skill downloads are public; MCP and business operations require authentication.
## Python Helper
Store the API Key outside the repository at `~/.config/genarrative/external-editor-api.json`:
```json
{
"apiKey": "tnr_sk_..."
}
```
Set restrictive permissions where possible, then smoke-test without printing the key:
```bash
chmod 600 ~/.config/genarrative/external-editor-api.json
python3 .codex/skills/genarrative-external-editor-api/scripts/genarrative_external_api.py list-projects
```
Its `prepare_canvas_session` convenience method creates or reuses a project and a same-name folder. Use it only when that organization matches the task; it is not a prerequisite for MCP or REST calls. Convenience generation methods wait locally while the server uses short asynchronous submit/status requests. Use `submit_generation`, `get_generation`, and `wait_for_generation` for caller-controlled orchestration; see [requests and outputs](references/requests-and-outputs.md).
For a canvas-backed generation:
Stay within `/api/external/v1` for this integration. Internal workers, queues, admin/profile APIs, and SpacetimeDB endpoints are outside this contract.
```python
from genarrative_external_api import GenarrativeExternalClient
client = GenarrativeExternalClient()
session = client.prepare_canvas_session("新画板")
client.generate_image(
"生成一张 16:9 幻想森林游戏背景",
canvasSession=session,
assetLabel="森林背景",
aspectRatio="16:9",
imageSize="1K",
artSpec={
"assetType": "background",
"subject": "幻想森林主视觉",
"style": "手绘游戏概念图",
"palette": "翡翠绿与金色光斑",
"composition": "横版,中心留出角色站位",
"format": "16:9, 1K",
"constraints": "无文字、无 UI 按钮",
"references": [],
},
)
```
For background removal, pass a stable owner-scoped object key, project resource ID, or asset ID; the helper keeps the same asynchronous submission and polling contract:
```python
session = client.prepare_canvas_session("去背景画布")
client.remove_background(
"editor-upload/object.png",
source_width=720,
source_height=1280,
canvasSession=session,
assetLabel="去背景结果",
)
```
Background removal preserves the source pixel size. For normal canvas placement with `canvasSession`, pass the real `source_width` and `source_height`, or provide both `canvasWidth` and `canvasHeight`; the helper rejects missing dimensions instead of guessing a square placeholder. `assetKind` may only describe a static image and must match the authoritative source record. Prefer a project resource ID or asset ID when the same object key has multiple semantic registrations; for a raw object key outside in-place replacement, pass `sourceResourceId` to disambiguate. Passing `targetLayerId` selects in-place replacement: the helper retains the session's project/library context but does not inject `canvasCompletion`, and it rejects an explicit `canvasCompletion` combined with `targetLayerId`. The target layer must point to the same authoritative object as the source, and the server durably binds a raw object key to that target resource for Worker revalidation.
Helper convenience methods wait locally, but the server still uses short asynchronous submit/status requests. For durable caller-controlled orchestration, call `submit_generation`, persist its `operationId` and idempotency key, then call `get_generation` or `wait_for_generation`.
For character animation, pass the canvas session and asset label to `animate_character`. The helper submits asynchronously and returns the completed compact result containing the authoritative formal `resource` and `asset`; do not synthesize a library asset from the first frame.
## Guardrails
- Do not change the fixed production base URL in generated examples.
- Do not move the API Key into environment variables, source files, generated projects, logs, docs, screenshots, or shell snippets containing literal secrets.
- Do not treat a Data URL, Blob URL, expiring signed URL, worker lease, or provider diagnostic as a durable result.
- Do not reconstruct authoritative canvas, resource, or library snapshots from a compact generation response.
- Do not replace icon-spritesheet generation with ordinary image generation when the deliverable requires a reusable transparent atlas.
@@ -4,45 +4,6 @@ Use this reference after selecting a capability. Treat `GET /api/external/v1/ope
All paths below are relative to `https://www.genarrative.world`. Discovery and Skill download routes are public. Project, asset, upload, generation, and generation-query operations require the Bearer API Key.
## MCP Tool to API Map
The hosted MCP offers the following tools. Choose the task tool when its action matches the request; the operation tool calls the indicated REST operation directly. Task tools with actions take `{ "action": "...", "input": { ... } }`; tools without actions take the operation fields directly. `idempotencyKey` is top-level in task tools. Operation tools use `body`, `pathParameters`, and `queryParameters` wrappers from their live input schemas. Read the live tool schema and OpenAPI for exact required fields.
| REST operation | Task tool (action) | Operation tool |
| --- | --- | --- |
| `GET /api/external/v1/openapi.json` | — | `get_external_open_api_json` |
| `GET /api/external/v1/editor/projects` | `find_canvas_projects` (`list`) | `list_editor_projects` |
| `GET /api/external/v1/editor/projects/recent` | `find_canvas_projects` (`recent`) | `load_recent_editor_project` |
| `GET /api/external/v1/editor/projects/{projectId}` | `find_canvas_projects` (`get`), `find_assets` (`get_project_resources`), `edit_canvas` (`get`) | `get_editor_project` |
| `POST /api/external/v1/editor/projects` | `manage_canvas_projects` (`create`) | `create_editor_project` |
| `PATCH /api/external/v1/editor/projects/{projectId}/metadata` | `manage_canvas_projects` (`rename`) | `rename_editor_project` |
| `DELETE /api/external/v1/editor/projects/{projectId}` | `delete_resources` (`delete_project`) | `delete_editor_project` |
| `PATCH /api/external/v1/editor/projects/{projectId}/canvas` | `edit_canvas` (`save_layout`) | `save_editor_project_canvas` |
| `POST /api/external/v1/editor/projects/{projectId}/resources` | `edit_canvas` (`register_resource`) | `create_editor_project_resource` |
| `POST /api/external/v1/assets/direct-upload-tickets` | `prepare_asset_upload` (`create_upload_ticket`) | `create_external_direct_upload_ticket` |
| `POST /api/external/v1/assets/objects/confirm` | `prepare_asset_upload` (`confirm_upload`) | `confirm_external_asset_object` |
| `GET /api/external/v1/assets/read-url` | `find_assets` (`get_download_url`) | `get_external_asset_read_url` |
| `GET /api/external/v1/editor/assets/library` | `find_assets` (`list_library`) | `get_editor_asset_library` |
| `POST /api/external/v1/editor/assets/folders` | `organize_asset_library` (`create_folder`) | `create_editor_asset_folder` |
| `PATCH /api/external/v1/editor/assets/folders/{folderId}` | `organize_asset_library` (`update_folder`) | `update_editor_asset_folder` |
| `DELETE /api/external/v1/editor/assets/folders/{folderId}` | `delete_resources` (`delete_folder`) | `delete_editor_asset_folder` |
| `POST /api/external/v1/editor/assets` | `organize_asset_library` (`create_asset`) | `create_editor_asset` |
| `PATCH /api/external/v1/editor/assets/{assetId}` | `organize_asset_library` (`update_asset`) | `update_editor_asset` |
| `DELETE /api/external/v1/editor/assets/{assetId}` | `delete_resources` (`delete_asset`) | `delete_editor_asset` |
| `POST /api/external/v1/editor/images/generations` | `generate_image`, `modify_image` (`variation`, fixed `kind="quick-edit"`) | `generate_external_editor_image` |
| `POST /api/external/v1/editor/scenes/generations` | structured game-scene generation (no hosted MCP tool yet) | `generate_external_editor_scene` |
| `POST /api/external/v1/editor/images/edits` | `modify_image` (`edit`) | `edit_external_editor_image` |
| `POST /api/external/v1/editor/images/background-removals` | `modify_image` (`remove_background`) | `remove_external_editor_image_background` |
| `POST /api/external/v1/editor/icon-spritesheets/generations` | `generate_icon_spritesheet` | `generate_external_editor_icon_spritesheet` |
| `POST /api/external/v1/editor/ui-designs/assets/extractions` | `extract_ui_assets` | `extract_external_editor_ui_design_assets` |
| `POST /api/external/v1/editor/character-animations/generations` | `generate_character_animation` | `generate_external_editor_character_animation` |
| `POST /api/external/v1/editor/videos/generations` | `generate_video` | `generate_external_editor_video` |
| `POST /api/external/v1/editor/audios/sound-effects/generations` | `generate_audio` (`sound_effect`) | `generate_external_editor_sound_effect` |
| `POST /api/external/v1/editor/audios/background-music/generations` | `generate_audio` (`background_music`) | `generate_external_editor_background_music` |
| `GET /api/external/v1/generations/{operationId}` | `check_generation` | `get_external_editor_generation_job` |
The public `agent-integration.json`, `skill/SKILL.md`, and `skill.zip` routes and the MCP transport route are HTTP entry points, not callable MCP tools. The hosted resource URIs remain `genarrative://external-editor/skill`, `genarrative://external-editor/skill/references/capability-routing.md`, `genarrative://external-editor/skill/references/api-operations.md`, `genarrative://external-editor/skill/references/authentication-and-safety.md`, `genarrative://external-editor/skill/references/requests-and-outputs.md`, and `genarrative://external-editor/openapi`.
## Project and Canvas Operations
| Operation | Method and path | Minimum input |
@@ -62,7 +23,7 @@ Project listing supports two views:
- `view=full` is the REST default and returns the complete project, canvas, layers, and resources.
- `view=summary` returns only `projectId`, `title`, `updatedAt`, and nullable `cover`, so callers can display, search, disambiguate same-name projects, and select a safe target without loading every canvas snapshot.
- Hosted MCP `list_editor_projects` and `find_canvas_projects` (`list`) use `summary`; call `get_editor_project` or `find_canvas_projects` (`get`) after selecting a `projectId` when complete authoritative state is required.
- Hosted MCP `list_editor_projects` always uses `summary`; call `get_editor_project` after selecting a `projectId` when complete authoritative state is required.
- `cover` contains only `resourceId`, stable `objectKey`, dimensions, and `updatedAt`. It never embeds image bytes, a Data URL, or a signed URL. To display it, pass `cover.objectKey` to `get_external_asset_read_url`; signed URLs are temporary and must not be persisted or reused as generation references.
## Asset and Upload Operations
@@ -81,7 +42,6 @@ Project listing supports two views:
| Delete asset record | `DELETE /api/external/v1/editor/assets/{assetId}` | `assetId` |
Upload is a three-step client flow: create a ticket, POST the file and returned fields directly to the OSS form endpoint, then confirm the returned `objectKey`. See `authentication-and-safety.md` before implementing this flow.
`prepare_asset_upload` handles the ticket and confirmation as separate calls; it does not send local bytes to OSS or automatically register a project resource, asset record, or canvas layer. `manage_canvas_projects` (`create`) likewise does not create a same-name asset folder. Register or organize records only when the task needs them.
## Generation Operations
@@ -90,17 +50,16 @@ Every generation row requires a stable `Idempotency-Key` header and returns HTTP
| Capability | POST path | Required body fields | Common optional body fields |
| ------------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Image generation | `/api/external/v1/editor/images/generations` | `prompt` | `kind`, `style`, `model`, `aspectRatio`, `imageSize`, `size`, `referenceImageSrcs`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion`, `generationInputs` |
| Game scene | `/api/external/v1/editor/scenes/generations` | `sceneContent`, `stylePreset` | `customStyle` (required when `stylePreset="custom"`), `model`, `aspectRatio`, `imageSize`, `referenceImageSrcs`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion`, `generationInputs` |
| Image edit/redraw | `/api/external/v1/editor/images/edits` | `prompt`, `sourceReferenceId` | `referenceImageSrcs`, `model`, `size`, `projectId`, `assetFolderId`, `assetLabel`, `targetLayerId`, `canvasCompletion` |
| Background removal | `/api/external/v1/editor/images/background-removals` | `sourceImageSrc` | `projectId`, `sourceResourceId`, `targetLayerId`, static-image `assetKind`, `assetFolderId`, `assetLabel`, `canvasCompletion`, `generationInputs` |
| Icon spritesheet | `/api/external/v1/editor/icon-spritesheets/generations` | `referenceId`, `iconDescriptions`, `sliceMode` | `gridX`, `gridY`, `sliceCount`, `style`, `referenceImageSrcs`, `screenColor`, `model`, `aspectRatio`, `imageSize`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion` |
| Icon spritesheet | `/api/external/v1/editor/icon-spritesheets/generations` | `referenceId`, `iconDescriptions` | `sliceMode`, `gridX`, `gridY`, `sliceCount`, `style`, `referenceImageSrcs`, `screenColor`, `model`, `aspectRatio`, `imageSize`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion` |
| UI asset extraction | `/api/external/v1/editor/ui-designs/assets/extractions` | `sourceImageSrc`, `aspectRatio`, `imageSize` | `screenColor`, `model`, `referenceImageSrcs`, `projectId`, `assetFolderId`, `spritesheetLabel`, `canvasCompletion` |
| Character animation | `/api/external/v1/editor/character-animations/generations` | `sourceLayerId`, `sourceImageSrc`, `sourceWidth`, `sourceHeight`, `promptText`, `resolution`, `ratio`, `frameCount`, `durationSeconds`, `model` | `projectId`, `sourceResourceId`, `assetFolderId`, `assetLabel`, `canvasCompletion` |
| Video generation | `/api/external/v1/editor/videos/generations` | `prompt`, `model`, `aspectRatio`, `durationSeconds`, `resolution`, `mode`, `sound` | `referenceImageSrcs`, `referenceVideoSrcs`, `referenceAudioSrcs`, `webSearchEnabled`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion` |
| Sound effect | `/api/external/v1/editor/audios/sound-effects/generations` | `prompt` | `model`, `duration`, `loop`, `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion`, `generationInputs` |
| Background music | `/api/external/v1/editor/audios/background-music/generations` | `gptDescriptionPrompt`, `makeInstrumental` | `projectId`, `assetFolderId`, `assetLabel`, `canvasCompletion`, `generationInputs` |
Poll all ten through:
Poll all nine through:
```text
GET /api/external/v1/generations/{operationId}
@@ -110,10 +69,10 @@ Supply the `operationId` returned by submission. Poll no faster than `pollAfterM
## Canvas and Library Field Rules
- Pass `projectId` and `canvasCompletion` when the task calls for generated output in a canvas.
- Pass `assetFolderId` plus the relevant label field when the task calls for a library record. Neither destination requires the other, and their names need not match.
- Pass `projectId` and `canvasCompletion` to write generated output into the canvas.
- Pass `assetFolderId` plus `assetLabel` for image, edit, icon spritesheet, video, sound effect, and BGM operations when supported.
- UI extraction uses `assetFolderId` and `spritesheetLabel`.
- Character animation accepts `assetFolderId` and `assetLabel` and persists the generated sequence. Consume returned artifacts and persisted identities; never create a duplicate first-frame resource or asset.
- Character animation accepts `assetFolderId` and `assetLabel`. Its completed compact result directly returns the final `assetKind="character-animation"` resource and asset with `imageSequenceFrames` and `imageSequenceDurationMs`; never create a duplicate first-frame resource or asset.
- Background removal derives the final static-image `assetKind` from the authoritative source record. A conflicting request kind or any video, audio, animation, or image-sequence kind returns `400` before queueing. Without `canvasCompletion`, `targetLayerId` must point to the same authoritative object as `sourceImageSrc` (prefer `assetObjectId`, otherwise canonical bucket/object key).
- If a caller must manually create a `character-animation` resource or asset, put the authoritative frames and total sequence duration in `imageSequenceFrames` and `imageSequenceDurationMs`. Keep `generationInputs` replayable: it must not contain legacy runtime fields such as `characterAnimation`, `frames`, `previewVideoPath`, `frameCount`, `fps`, or `durationSeconds`.
- Reload project/library state after completion when full current state is required.
@@ -142,7 +101,7 @@ The icon-spritesheet primary `referenceId` is intentionally stricter than ordina
Use OpenAPI as the final authority; these common values are a routing aid:
- Image `kind`: `spec`, `character`, `quick-edit`, `ui-design`, `publication-material`; ordinary image generation may omit it.
- Game scenes must use the dedicated structured route `POST /api/external/v1/editor/scenes/generations` (`sceneContent` + `stylePreset`; `customStyle` required for `custom`). Do not send `kind: "scene"` or `assetKind: "scene"` through generic image generation; the server rejects both before queueing. The scene route assembles the full provider prompt server-side and never accepts a caller-assembled `prompt`.
- External v1 currently has no structured game-scene generation operation. Do not send `kind: "scene"` or `assetKind: "scene"` through generic image generation; the server rejects both before queueing.
- Image `model`: `gpt-image-2`, `gemini-3.1-flash-image-preview`, `nanobanana2`, `nano-banana`.
- Image `aspectRatio`: `1:1`, `2:3`, `3:2`, `9:16`, `16:9`.
- Image `imageSize`: `0.5K`, `1K`, `2K`.
@@ -21,7 +21,7 @@ Authorization: Bearer <tnr_sk_...>
Guide a logged-in user to create a key in the product UI under `开发者 API Key`. The raw key is shown only once. Never ask the user to paste it into chat.
For hosted MCP, configure the Bearer token in the client's private connection settings. For the bundled REST helper, store it outside repositories in the user's private JSON file:
Store it outside repositories in the user's private JSON file:
```text
~/.config/genarrative/external-editor-api.json
@@ -61,7 +61,7 @@ The OpenAPI document, integration manifest, raw Skill entry, and Skill archive a
For each logical generation:
1. Create one printable ASCII key of 1-128 bytes. MCP takes `idempotencyKey` at the top level of the tool arguments (outside `input`); REST takes the `Idempotency-Key` header.
1. Create one printable ASCII `Idempotency-Key` of 1-128 bytes.
2. Persist the key with the exact request body and returned `operationId`.
3. If submission transport fails or the response is lost, resend only the exact same body with the same key.
4. Never allocate a new key merely because the outcome is unknown.
@@ -69,21 +69,15 @@ For each logical generation:
Treat a different body under the same key as invalid. Do not automatically replay a failed terminal generation unless the user intentionally requests a new logical generation.
Keep the API operation as well as the request and key unchanged across a submission retry. A different tool name does not create a separate idempotency namespace. When an operation ID is known, query `check_generation` directly. A rejected submission is not permission to switch keys and generate again.
`manage_canvas_projects/create`, `edit_canvas/register_resource`, and `organize_asset_library/create_folder` accept optional top-level `idempotencyKey`. Other non-generation actions do not accept it; in particular, `create_asset` is not an idempotent generation submission.
## Local Reference Upload
Do not ask the user to convert local files to base64. Upload from the Agent/client machine:
1. Detect the original filename, MIME type, byte length, and image dimensions when relevant.
2. Call `prepare_asset_upload` with `action=create_upload_ticket` and the ticket body in `input` (REST: `POST /api/external/v1/assets/direct-upload-tickets`).
2. Create a ticket with `POST /api/external/v1/assets/direct-upload-tickets`.
3. POST all returned non-null `formFields` and the file part named `file` directly to `upload.host`.
4. Call `prepare_asset_upload` with `action=confirm_upload` and the confirmation body in `input` (REST: `POST /api/external/v1/assets/objects/confirm`).
5. Pass the confirmed stable `objectKey` where the selected tool permits it. For operations requiring a registered source, register a project resource or asset first and use its ID.
The MCP tool does not transfer file bytes and does not accept a local path or base64. The client needs an HTTP/file-transfer capability for step 3. Object ownership comes from the API Key; do not supply `ownerUserId`. Confirmation alone creates neither a library record nor a canvas layer.
4. Confirm the object with `POST /api/external/v1/assets/objects/confirm`.
5. Pass the confirmed stable `objectKey` to the selected editor operation.
For a private reference image, use a ticket body shaped like:
@@ -113,7 +107,7 @@ Confirm with the actual file metadata:
`contentLength` is a JSON number in bytes, not a quoted string. Never invent `sourceWidth` or `sourceHeight`; read them from the local image or ask the user if they cannot be determined.
For character animation, use source identity and dimensions from the actual selected resource; do not invent an existing canvas layer. The bundled local-file helper can maintain its own stable source label, which is not evidence of a persisted canvas layer.
For character animation, reuse a real canvas layer ID when available. For a local-only source, derive a stable synthetic `sourceLayerId`, such as `external-reference-hero`, from the filename and keep it unchanged across retries.
The bundled helper implements ticket creation, a stdlib multipart upload, confirmation, dimension detection for common formats, and stable source-layer IDs:
@@ -132,7 +126,7 @@ Do not print the complete confirmation response if it may contain temporary acce
- Use `objectKey`, project resource ID, asset ID, or an allowed durable public URL for generation input.
- Use a Data URL only when the endpoint explicitly allows it and the caller has a deliberate reason; do not persist it as a durable output.
- Never use a Blob URL outside the browser process that created it.
- Use `find_assets` with `action=get_download_url` (REST: `GET /api/external/v1/assets/read-url`) to obtain a short-lived `signedUrl` for display/download. This returns a URL; the client still performs any download.
- Use `GET /api/external/v1/assets/read-url` to obtain a short-lived `signedUrl` for display/download.
- Never store or feed an expiring signed URL back into generation when a stable `objectKey` exists.
## Logging and Command Safety
@@ -145,8 +139,6 @@ Do not print the complete confirmation response if it may contain temporary acce
## Scope and Retry Guardrails
- Generation spends account credits. Respect the user's authorized task and scope; do not restart generation merely because a requested derivative is missing.
- For `delete_resources`, identify the precise IDs and obtain authorization for the actual deletion scope. Project deletion cascades to its default canvas and project-resource metadata. Folder deletion moves its assets to the default folder; the default folder cannot be deleted. Deleting a folder or asset record does not delete the underlying OSS file.
- Do not use account JWT/profile endpoints as the default external integration. Logged-in profile APIs may create/revoke developer keys, but they are outside this external editor contract.
- Do not call internal workers, queues, SpacetimeDB, or admin endpoints.
- Do not bypass upload confirmation or invent an object key.
@@ -10,17 +10,21 @@ Use this reference to translate user intent into a hosted MCP tool or its corres
- Public contract: `GET /api/external/v1/openapi.json`.
- Skill fallback: `GET /api/external/v1/skill/SKILL.md` or `GET /api/external/v1/skill.zip`.
Prefer MCP when the Agent supports a remote endpoint plus a custom Bearer token. Prefer the complete Skill and Python helper when MCP is unavailable or a client-side local-file upload must be orchestrated. Choose a task-oriented tool below for ordinary requests, or the corresponding operation tool in [API Operations](api-operations.md) when the request needs direct control of one REST call. All 44 tools remain available. Discover the live tool schema before calling it; OpenAPI remains the field-level authority. The public discovery and Skill download routes are listed below, but are not MCP tools.
Prefer MCP when the Agent supports a remote endpoint plus a custom Bearer token. Prefer the complete Skill and Python helper when MCP is unavailable or a client-side local-file upload must be orchestrated. The MCP tool names are derived from OpenAPI `operationId` values in snake case; select by capability instead of memorizing the name.
## Project and Asset Destination
## Canvas Session
Use `find_canvas_projects` (`action=list`, `recent`, or `get`) to locate an existing canvas when the request involves one. Use `manage_canvas_projects` (`create` or `rename`) only when the user needs a project created or renamed. A new project does not create an asset folder automatically. Use `find_assets` and `organize_asset_library` when the task involves library records or folders. A project and folder may have different names, and either may be unnecessary for a standalone generation.
Before the first generation in a new conversation, obtain a canvas name unless the user already supplied an existing `projectId` and `assetFolderId`.
For generation, pass `projectId` with `canvasCompletion` when the result should enter a canvas, and `assetFolderId` with the endpoint's label field when it should enter the library. Use both only when the task requires both destinations. Character animation returns its final resource and asset directly when those destinations are requested; do not duplicate its first frame.
1. List or create a project. When creating one, use the canvas name as `title`.
2. Read the asset library. Reuse a folder with the same label or create one with the canvas name.
3. Retain `canvasName`, `projectId`, `assetFolderId`, and the current art spec in conversation state.
Generated artifacts must enter both the current canvas and its same-name library folder whenever the endpoint supports that invariant. Pass `projectId`, `assetFolderId`, the endpoint's label field, and `canvasCompletion`. Character animation returns the final formal resource and asset directly; use those records and never create a duplicate from the first frame.
## Art Spec Routing
For a series of related art requests, an optional reusable spec can carry the shared requirements:
Before art generation, normalize the user's request into:
```json
{
@@ -39,48 +43,48 @@ Infer what is already clear and ask only for missing fields that block the selec
## Intent Map
| User intent | MCP tool and action |
| --- | --- |
| Find, open, create, or rename a canvas project | `find_canvas_projects` (`list`, `recent`, `get`); `manage_canvas_projects` (`create`, `rename`) |
| Read project resources or library records | `find_assets` (`get_project_resources`, `list_library`) |
| Create or change folders and asset records | `organize_asset_library` (`create_folder`, `update_folder`, `create_asset`, `update_asset`) |
| Upload a local image/audio/video asset | `prepare_asset_upload` (`create_upload_ticket`), client-side OSS form upload, then `prepare_asset_upload` (`confirm_upload`) |
| Register existing media in a project, read a canvas, or save its full layout | `edit_canvas` (`register_resource`, `get`, `save_layout`) |
| Generate a background, character, spec, UI mockup, or publication image | `generate_image` |
| Retouch an existing image, make a reference variation, or remove its background | `modify_image` (`edit`, `variation`, `remove_background`) |
| Build a transparent icon/game atlas from a registered visual spec | `generate_icon_spritesheet` |
| Generate marked assets from an existing UI design | `extract_ui_assets` |
| Animate a character into frames | `generate_character_animation` |
| Generate video | `generate_video` |
| Generate a sound effect or background music | `generate_audio` (`sound_effect`, `background_music`) |
| Check generation progress or retrieve its result | `check_generation` |
| Obtain temporary access to private media | `find_assets` (`get_download_url`) |
| Delete an exact project, folder, or asset record | `delete_resources` (`delete_project`, `delete_folder`, `delete_asset`) |
For tools with actions, send `{ "action": "...", "input": { ... } }`; place `idempotencyKey` at the top level when supported or required. Tools without actions accept operation fields directly, with `idempotencyKey` at the top level for generation. The direct operation tools use `body`, `pathParameters`, and `queryParameters` wrappers as shown by their live schemas.
| User intent | MCP/REST capability |
| ----------------------------------------------------------------------- | ---------------------------------------------------------------- |
| Generate a background, character, spec, UI mockup, or publication image | Image generation |
| Redraw, retouch, or replace an existing image | Image edit |
| Remove the background from an existing image | Background removal |
| Generate from a local reference | Upload and confirm the local file, then image generation or edit |
| Build a reusable transparent icon/game atlas from a visual spec | Icon spritesheet generation |
| Extract marked assets from an existing UI design | UI design asset extraction |
| Animate a character into frames | Character animation generation |
| Generate video | Video generation |
| Generate a sound effect | Sound-effect generation |
| Generate background music/BGM | Background-music generation |
| Upload a local image/audio/video asset | Upload ticket -> OSS form upload -> object confirm |
| Save viewport/layers | Canvas save |
| Create, load, rename, or delete a canvas | Project operations |
| Organize folders and asset records | Asset-library operations |
| Obtain temporary access to private media | Signed read URL |
| Check generation progress or retrieve its result | Generation query |
Do not present an API menu unless the request is genuinely ambiguous. Ask a follow-up when two routes create different artifacts, for example “处理这张图” could mean edit, extract marked UI assets, or use it as a reference for a new generation.
## Route-Specific Decisions
- Use `modify_image` `edit` when the requested output modifies a registered source image. Use `variation` when reference images should guide a new `quick-edit` image; it is image generation with fixed `kind="quick-edit"`. Use `remove_background` for a static source image. With `projectId`, `targetLayerId` may replace a matching existing layer when no explicit `canvasCompletion` is supplied.
- Use image edit when the requested output replaces or modifies a source image. With `projectId`, pass `targetLayerId` to replace an existing layer when no explicit `canvasCompletion` is supplied.
- Use icon spritesheet generation for a transparent reusable atlas when a stable visual-spec reference and concrete `iconDescriptions` exist. Do not use ordinary image generation just because it can draw several objects.
- Use UI extraction only for an existing UI design image with red-box annotations. It is not UI generation.
- Character animation requires a real `sourceLayerId`, source image, and dimensions from an existing resource. A local-only file must first be uploaded and registered where needed; do not invent a layer ID.
- Use a project layer ID as character animation `sourceLayerId` when one exists. For a local-only source, derive a stable synthetic ID from the filename.
- For video with image/video/audio references, use a Seedance 2.0-family model; default to `seedance2.0-fast`, `mode: "std"`, and explicit `sound`.
- `prepare_asset_upload` obtains a ticket and confirms an uploaded object; it does not transfer the file or register a project resource, asset record, or canvas layer. Use `edit_canvas` `register_resource` or `organize_asset_library` `create_asset` only when the task needs those records.
- Use temporary signed URLs only for preview/download. Feed stable `objectKey` or registered resource/asset identifiers into generation as each operation permits.
- Use `signedUrl` only for preview/download. Feed stable `objectKey` or registered resource/asset identifiers into generation.
## Example: Reusable Icon Assets
## AI Game Creator Canonical Visual DAG
When the task needs a visual spec and a reusable icon atlas:
Keep the existing autonomous-build task graph. Do not add a parallel task system or collapse these artifacts into one ordinary generation request:
1. Reuse an existing registered `icon-spec`, or generate the requested spec using `generate_image` with `kind=spec` and register it as `assetKind=icon-spec` if necessary.
2. Call `generate_icon_spritesheet` with that registered ID as `referenceId`, concrete `iconDescriptions`, and explicit `sliceMode`. Choose `grid` only for requested equal cells or fixed slots and provide those `gridX`/`gridY` values; otherwise use `connected-components`, optionally with `sliceCount`.
3. Query `check_generation` and inspect the full sheet and actual slices. Preserve warnings; a usable full sheet does not imply that individual slices exist. Use returned slice identities and dimensions rather than guessing crop coordinates.
1. `art-director` generates `assets/art-spec.png` with image generation, `kind: "spec"`, then registers it as `assetKind: "icon-spec"`. This image is the authoritative visual spec; `generationInputs.artSpec` is supporting structured context.
2. `design-foundation` generates `assets/ui-prototype.png` with `kind: "ui-design"`, using the registered art-spec resource ID in `referenceImageSrcs`.
3. `art-asset-plan` generates transparent `assets/art-spritesheet.png` through icon spritesheet generation, using the same registered art-spec resource ID as `referenceId` plus concrete `iconDescriptions`. `sliceMode` is required and has no default: send `sliceMode: "grid"` with `gridX`/`gridY` only when the requirement itself fixes the slots or names the column/row count, and otherwise send `sliceMode: "connected-components"` (with `sliceCount` when a subject count must be constrained); never invent a grid to express "kinds of assets", and never send `gridX`/`gridY` with `connected-components`.
An ordinary UI mockup or uploaded image is not automatically an `icon-spec`. For extracting marked components from a UI design, use `extract_ui_assets`, which includes generation and does not promise pixel-exact cropping.
For a playable Canvas game, do not stop at generation. Make `code-prototype` depend on `art-asset-plan` and consume the persisted `iconImageSrcs` slices for core players, blocks or targets, scene obstacles, and feedback. When the requirement fixes grid slots, require the response `sliceMode` to match the declared `grid` request and exactly `gridX × gridY` slices before registering the local runtime sheet; a connected-components request is instead judged by its own `sliceCount` or by the requirement, and both fewer and extra components fail closed. Treat `art-spec.png` as reference-only. A full-sheet `<img>`, CSS background, path-only mention, guessed equal-grid crop, or code-drawn replacement for core entities is not runtime asset use. If slicing produces `sliceWarning`, keep the complete transparent sheet as a valid editor artifact, but fail the playable game asset gate until real slice files or verified atlas coordinates exist; never invent coordinates or replace the icon-spritesheet route with ordinary image generation.
Never use `assets/ui-prototype.png` as the spritesheet visual-spec reference. UI extraction is outside this canonical DAG.
## Scope Boundary
Stay within `/api/external/v1`. Do not invent worker, queue, runtime task-list, admin, profile, or SpacetimeDB calls. The only external generation query is `GET /api/external/v1/generations/{operationId}`. The hosted MCP also exposes the Skill and OpenAPI resources at `genarrative://external-editor/skill`, its four `skill/references/*.md` URIs, and `genarrative://external-editor/openapi`; keep those URI names unchanged.
Stay within `/api/external/v1`. Do not invent worker, queue, runtime task-list, admin, profile, or SpacetimeDB calls. The only external generation query is `GET /api/external/v1/generations/{operationId}`.
@@ -4,46 +4,15 @@ Use this reference to build generation payloads, carry canvas/library context, p
## Contents
- [MCP Argument Shapes](#mcp-argument-shapes)
- [Asynchronous Submission](#asynchronous-submission)
- [Polling State Machine](#polling-state-machine)
- [Canvas and Asset-Library Completion](#canvas-and-asset-library-completion)
- [Saving Existing Canvas Layout](#saving-existing-canvas-layout)
- [Art Spec and Image Request](#art-spec-and-image-request)
- [Local Reference Requests](#local-reference-requests)
- [Compact Completed Result](#compact-completed-result)
- [Warning Semantics](#warning-semantics)
- [Output Handling Checklist](#output-handling-checklist)
## MCP Argument Shapes
Pass these objects as the `arguments` of the named tool in `tools/call`. They are not REST request envelopes.
Single-function tools take business fields directly. For example, `generate_image`:
```json
{
"prompt": "一张横版幻想森林背景,无文字",
"aspectRatio": "16:9",
"imageSize": "1K",
"idempotencyKey": "forest-image-001"
}
```
Multi-function tools take `action` and `input`. A generation key stays outside `input`. For example, `generate_audio`:
```json
{
"action": "sound_effect",
"input": {"prompt": "轻柔的游戏菜单确认音", "duration": 1},
"idempotencyKey": "menu-sound-001"
}
```
Keys above identify distinct example requests; create and persist your own key for each new logical generation. An action with no business fields still requires `input: {}`, such as `find_canvas_projects` with `action=list`. Use only fields belonging to the selected action; do not combine branches. REST examples below use the business body directly and put the key in the HTTP header instead.
MCP returns business data in `structuredContent`, without the REST `data` envelope. Check `isError` before using it; an HTTP-successful MCP exchange can still carry a tool error. Generation acceptance contains an `operationId`, not the final media.
## Asynchronous Submission
All nine generation POST routes require `Idempotency-Key` and return HTTP `202` with an `ExternalEditorGenerationSubmissionResponse` shaped like:
@@ -81,7 +50,7 @@ Persist the key, exact request body, and `operationId`. If submission outcome is
## Polling State Machine
With MCP, call `check_generation` with `{"operationId":"<returned operationId>"}`. Each call queries once and does not wait for completion. With REST, poll `statusUrl` or `GET /api/external/v1/generations/{operationId}`. Query no faster than `pollAfterMs`:
Poll `statusUrl`, or `GET /api/external/v1/generations/{operationId}`, no faster than `pollAfterMs`:
- `queued` / `running`: retain `operationId`; show `phaseLabel`, `phaseDetail`, and `progress` when present; wait before querying again.
- `completed`: consume the compact `result` and all warning fields, then stop polling.
@@ -106,10 +75,10 @@ Background removal uses the same submission and polling state machine. `sourceIm
## Canvas and Asset-Library Completion
Choose destinations according to the task. Locate an existing project with `find_canvas_projects` and inspect folders with `find_assets/list_library`; create missing destinations with `manage_canvas_projects/create` and `organize_asset_library/create_folder` only when needed. Project creation does not create a folder. For endpoints that support the requested destinations, include:
For endpoints that support these fields, include:
- `projectId`: target canvas project.
- `assetFolderId`: target asset-library folder; its name need not match the project.
- `assetFolderId`: folder whose label matches the canvas name.
- `assetLabel` or UI extraction's `spritesheetLabel`: user-visible library label.
- `canvasCompletion`: backend canvas placement instructions.
@@ -133,24 +102,15 @@ A minimal `canvasCompletion` is:
Background removal preserves the source image dimensions. For normal canvas placement, the Python helper therefore requires the real `source_width` and `source_height` whenever `canvasSession` is used without an explicit `canvasWidth` plus `canvasHeight`; it never substitutes a square default. Passing `targetLayerId` instead selects in-place replacement, so the helper keeps the session's project/library fields without injecting `canvasCompletion` and rejects callers that explicitly combine both placement modes. The request `assetKind` is optional, static-image only, and must equal the authoritative source type when one exists. An in-place target must resolve to the same authoritative source object; a raw object key is bound to that target resource instead of relying on project-list order.
Character animation accepts `assetFolderId` and `assetLabel` and persists the generated sequence. Consume the returned animation artifacts and persisted identities; do not synthesize a duplicate animation asset from the first frame. Use complete project/library records when complete persisted state is needed.
Character animation accepts `assetFolderId` and `assetLabel` and persists the final transparent sequence directly. Its completed compact result includes the authoritative `assetKind="character-animation"` resource and asset with `imageSequenceFrames` and `imageSequenceDurationMs`. Use those records directly and never synthesize a duplicate asset from the first frame.
For the lower-level asset/resource creation endpoints, `generationInputs` is replayable request context rather than a media-runtime container. When `assetKind` is `character-animation`, the server rejects legacy runtime keys including `characterAnimation`, `frames`, `previewVideoPath`, `frameCount`, `fps`, and `durationSeconds`; send the formal sequence through `imageSequenceFrames` and `imageSequenceDurationMs`. Internal processing audit keys such as `screenColorHex`, `mattingProvider`, and `mattingModel` are removed before persistence.
## Saving Existing Canvas Layout
1. Call `edit_canvas` with `action=get` and `input.projectId` to read the latest project and canvas revision.
2. Build the intended complete `viewport` and `layers`, preserving unrelated layers. `save_layout` replaces the layout; it is not a one-layer patch.
3. Call `edit_canvas` with `action=save_layout` and `input` containing `projectId`, the read `expectedRevision`, and the complete `viewport` and `layers`.
4. On a revision conflict, reread and reconcile with the current layout before retrying. Do not blindly resend stale layers with a refreshed revision.
`edit_canvas/register_resource` registers existing media but does not create a canvas layer. `organize_asset_library/create_asset` creates metadata but does not upload or generate media. For generated media placement, prefer the generation tool's supported `canvasCompletion`; inspect returned identities before registering anything again.
## Art Spec and Image Request
Game scenes have a dedicated structured route: `POST /api/external/v1/editor/scenes/generations` with `sceneContent` and `stylePreset` (`customStyle` required when `stylePreset` is `custom`). The server assembles the full provider prompt; a caller-assembled `prompt` is not accepted. `kind: "scene"` and `assetKind: "scene"` remain invalid on generic image generation and return HTTP `400` before any generation job is queued.
Generic External v1 image generation does not expose the main-site structured game-scene contract. `kind: "scene"` and `assetKind: "scene"` are both invalid and return HTTP `400` before any generation job is queued. Do not replace the structured scene fields and server-owned prompt assembly with a generic image prompt.
When maintaining a reusable art spec, carry it in `generationInputs.artSpec` and reflect important constraints in the prompt. This is an example with both canvas and library destinations, not a requirement for every generation:
Carry the current art spec in `generationInputs.artSpec` and reflect important constraints in the prompt:
```json
{
@@ -217,11 +177,11 @@ Image edit/redraw has a stricter main-source identity rule. After upload confirm
Icon spritesheet generation has a stricter primary-spec contract. After upload confirmation, create a project resource or asset record with `assetKind: "icon-spec"`, retain its returned `resourceId` or `assetId`, and pass that ID as `referenceId`. The primary spec does not accept the uploaded `objectKey` directly; only additional style references may continue to use stable object keys in `referenceImageSrcs`.
For character animation, use the selected source identity and actual dimensions. The following is a business-body example; `generate_character_animation` also requires a top-level `idempotencyKey`:
For character animation from a local-only source, use actual dimensions and a stable synthetic layer ID:
```json
{
"sourceLayerId": "<selected source layer ID>",
"sourceLayerId": "external-reference-hero",
"sourceImageSrc": "<confirmed objectKey>",
"sourceWidth": 720,
"sourceHeight": 1280,
@@ -249,7 +209,7 @@ The completed `result` may contain stable artifact fields such as:
- `spritesheetResource`, `spritesheetAsset`, and stable spritesheet metadata.
- `warning` and `sliceWarning` structures.
It deliberately excludes a complete project/canvas/library snapshot, Data URL, Blob URL, expiring signed URL, worker lease, queue state, and internal provider diagnostics. Use `find_assets/get_download_url` for temporary access to a stable `objectKey` (REST: `/assets/read-url`). Reading a record or obtaining a URL does not itself inspect or download the media.
It deliberately excludes a complete project/canvas/library snapshot, Data URL, Blob URL, expiring signed URL, worker lease, queue state, and internal provider diagnostics. Use `/assets/read-url` for temporary access to a stable `objectKey`.
## Warning Semantics
-1
View File
@@ -65,7 +65,6 @@ temp*build*/
/apps/preview-deployer-web/node_modules/
/server-rs/.spacetimedb/
/server-rs/.data/
**/server-rs/.data/
/public/generated-animations
/public/generated-character-drafts
/public/generated-characters
-33
View File
@@ -48,23 +48,6 @@ _Avoid_: 无来源的静态素材、只显示在 UI 但不落工程资源记录
一组同类素材的统一批量生成方式,采用批量规划、sheet 生图、后端切图、透明化、OSS 持久化和局部重生成的通用流水线。
_Avoid_: 为每个玩法单独发明素材流水线、把系列素材建模成任一玩法专属 DTO
**UI 设计文档**:
AGC 本地项目里 `kind=ui-design-doc`、`mediaType=application/json` 的界面编辑载体,保存设计图集合、UI 树、组件绑定和 State revision;一份文档可同时承载多张设计图与各自的结构树,不强制收敛成一棵树。
_Avoid_: 把 UI 设计图当成设计文档、给设计文档再套一层「页面」概念
**设计图**:
UI 设计文档里的一张参考界面图,以它在 manifest 中的资产 ID 作为文档内身份,附带像素尺寸与像素比;文档内的每棵树都必须引用文档里已存在的设计图。
_Avoid_: 用文件名当设计图身份、设计图与设计文档同一概念
**UI 工作流步骤**:
对一份 UI 设计文档执行的一次受控处理阶段,当前只有「结构识别」与「素材切分」两步;步骤产物只有在写入文档并保存后才算完成。
_Avoid_: 把单次工具调用当成步骤、把中间产物当成步骤完成
**工作流检查点日志**:
一份 UI 设计文档旁按行追加的恢复用日志,每完成一个工作流步骤追加一行;某步是否有对应行即代表该步是否完成,恢复时从第一个缺失的行继续。
_Avoid_: 每步一个 sidecar 状态机、把切分专用的 SeparationState 泛化成通用检查点
## Language
### Puzzle Clear
@@ -207,22 +190,6 @@ _Avoid_: 会话缓存、展示态历史、按 UI 需要另存的对话副本
Thread Manager 向订阅者推送的当前回合原始事件流,只服务运行期间与短期断线恢复,不替代项目对话历史。
_Avoid_: 进度通知、快照轮询、第二套历史
**逻辑回合**:
Thread Manager 拥有的一对回合边界(开始与结束),由接单动作开启、由这一轮的占用对象写出,不镜像 Codex 原生回合;界面忙碌态与回合结果只认它。
_Avoid_: Codex 原生回合、原生日志、进程生命周期
**接单**:
把一条用户消息交给宿主开始执行的动作,成立即表示这一轮已经存在;此后结果只由运行态事件回答。
_Avoid_: 发送成功、命令调用、接口返回
**拒单**:
接单成立之前拒绝这次请求(并发、权限、目录、参数、工程准备未就绪),只回一条可展示原因,不产生回合事件,也不写用户条目。
_Avoid_: 回合失败、执行失败、失败事件
**在途回合**:
界面本地已经把这条用户消息发出去、宿主还没有对应回合开始事件的那一小段状态。
_Avoid_: 运行中回合、乐观锁、发送队列
**聊天投影**:
把项目对话历史条目与运行态事件转换成消息气泡和工具卡片的读取期转换;不持久化,也不构成事实源。
_Avoid_: 投影缓存文件、已脱敏卡片库、第二套 reducer
@@ -6,7 +6,7 @@
"visibleModels": [],
"apiKey": "",
"baseUrl": "https://dev.genarrative.world/gpt/v1",
"model": "platform-default",
"model": "gpt-6-astra",
"apiKind": "openai_responses",
"reasoningEffort": "max",
"stream": true,
@@ -157,8 +157,11 @@ const allowedUncalledTauriCommands = [
'set_active_game_creator_agent_session',
'start_game_creator_agent_goal',
'start_game_creator_supervisor_runtime_task',
// TODO: Remove the retired binding command after the legacy runtime path is removed.
'bind_components',
'chat_with_game_creator_agent',
'check_ui_editor_font_glyph_coverage',
'create_ui_design_resource',
// 图片类生成的同步变体:GUI 已改为 `start_local_project_asset_generation` + 项目内任务账本
// (提交即返回、后台生成)。这条命令**没有生产调用方**,只有 Rust 集成测试
// (`src/tests/project.rs`)与 `commands.rs` 单测在调;待后续批次删除,或改为转调
@@ -1494,15 +1497,6 @@ if (defaultAppConfig.llm?.apiKey !== '') {
throw new Error('AI game creator shell default llm.apiKey must stay empty');
}
// 首次启动模板必须写入官方路由占位模型(与 config.rs 的
// OFFICIAL_LLM_ROUTER_DEFAULT_MODEL 同源):钉死具体上游模型名会随上游目录
// 变动失效,留空则首启配置不合法。
if (defaultAppConfig.llm?.model !== 'platform-default') {
throw new Error(
'AI game creator shell default llm.model must stay the official route placeholder',
);
}
if (defaultAppConfig.agentMode !== 'codex_app_server') {
throw new Error(
'AI game creator shell default agentMode must be codex_app_server',
@@ -1,7 +1,5 @@
#[path = "build_support/codex_bundle.rs"]
mod codex_bundle;
#[path = "build_support/codex_package_metadata.rs"]
mod codex_package_metadata;
#[path = "build_support/frontend_dist_guard.rs"]
mod frontend_dist_guard;
#[path = "build_support/godot_bundle.rs"]
@@ -66,7 +64,7 @@ fn stage_codex_target(manifest_dir: &std::path::Path, target: &str) {
.parent()
.and_then(|apps_dir| apps_dir.parent())
.expect("AI 游戏创作应用必须位于仓库 apps 目录下");
let package = format!("codex-{}", layout.platform);
let package = layout.npm_package;
let source_candidates = [app_root, repo_root]
.into_iter()
.flat_map(|root| {
@@ -101,7 +99,7 @@ fn stage_codex_target(manifest_dir: &std::path::Path, target: &str) {
&fs::read(source.join("codex-package.json")).expect("读取 Codex 原生包元数据失败"),
)
.expect("Codex 原生包元数据无效");
codex_package_metadata::validate_package_metadata(&metadata, target, layout)
codex_bundle::validate_package_metadata(&metadata, target, layout)
.unwrap_or_else(|error| panic!("{error}"));
let target_dir = manifest_dir.join("resources/codex").join(layout.directory);
let notice = target_dir.join("NOTICE.md");
@@ -7,6 +7,7 @@ pub const SCHEMA: &str = "genarrative-codex-sidecar.v2";
#[derive(Clone, Copy, Debug)]
pub struct Layout {
pub platform: &'static str,
pub npm_package: &'static str,
pub directory: &'static str,
pub executable: &'static str,
pub files: &'static [&'static str],
@@ -32,6 +33,7 @@ pub fn for_target(target: &str) -> Option<Layout> {
match target {
"x86_64-pc-windows-msvc" => Some(Layout {
platform: "win32-x64",
npm_package: "codex-win32-x64",
directory: "win-x64",
executable: "bin/codex.exe",
files: WINDOWS_FILES,
@@ -42,6 +44,11 @@ pub fn for_target(target: &str) -> Option<Layout> {
} else {
"darwin-x64"
},
npm_package: if target.starts_with("aarch64") {
"codex-darwin-arm64"
} else {
"codex-darwin-x64"
},
directory: if target.starts_with("aarch64") {
"mac-native/darwin-arm64"
} else {
@@ -54,6 +61,24 @@ pub fn for_target(target: &str) -> Option<Layout> {
}
}
pub fn validate_package_metadata(
metadata: &serde_json::Value,
target: &str,
layout: Layout,
) -> Result<(), String> {
if metadata["layoutVersion"] == 1
&& metadata["version"] == VERSION
&& metadata["target"] == target
&& metadata["entrypoint"] == layout.executable
&& metadata["resourcesDir"] == "codex-resources"
&& metadata["pathDir"] == "codex-path"
{
Ok(())
} else {
Err(format!("Codex 原生包版本、布局或架构不匹配目标 {target}"))
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -62,11 +87,13 @@ mod tests {
fn platform_layouts_are_explicit_and_preserve_upstream_components() {
let mac = for_target("aarch64-apple-darwin").unwrap();
assert_eq!(mac.platform, "darwin-arm64");
assert_eq!(mac.npm_package, "codex-darwin-arm64");
assert!(mac.files.contains(&"codex-resources/zsh/bin/zsh"));
assert!(mac.files.contains(&"bin/codex-code-mode-host"));
assert!(!mac.files.iter().any(|file| file.ends_with(".exe")));
let intel = for_target("x86_64-apple-darwin").unwrap();
assert_eq!(intel.platform, "darwin-x64");
assert_eq!(intel.npm_package, "codex-darwin-x64");
assert_eq!(mac.directory, "mac-native/darwin-arm64");
assert_eq!(intel.directory, "mac-native/darwin-x64");
assert_ne!(mac.directory, intel.directory);
@@ -80,4 +107,34 @@ mod tests {
assert!(for_target("aarch64-pc-windows-msvc").is_none());
assert!(for_target("x86_64-unknown-linux-gnu").is_none());
}
#[test]
fn metadata_rejects_version_architecture_and_layout_drift() {
let target = "aarch64-apple-darwin";
let layout = for_target(target).unwrap();
let valid = serde_json::json!({
"layoutVersion": 1,
"version": VERSION,
"target": target,
"entrypoint": "bin/codex",
"resourcesDir": "codex-resources",
"pathDir": "codex-path",
});
assert!(validate_package_metadata(&valid, target, layout).is_ok());
for (key, value) in [
("layoutVersion", serde_json::json!(2)),
("version", serde_json::json!("0.0.0")),
("target", serde_json::json!("x86_64-apple-darwin")),
("entrypoint", serde_json::json!("bin/codex.exe")),
("resourcesDir", serde_json::json!("../private")),
("pathDir", serde_json::json!(null)),
] {
let mut invalid = valid.clone();
invalid[key] = value;
assert!(
validate_package_metadata(&invalid, target, layout).is_err(),
"{key}"
);
}
}
}
@@ -1,57 +0,0 @@
//! 随包阶段的原生包元数据校验,不进入运行时生产模块。
use super::codex_bundle::{Layout, VERSION};
pub fn validate_package_metadata(
metadata: &serde_json::Value,
target: &str,
layout: Layout,
) -> Result<(), String> {
if metadata["layoutVersion"] == 1
&& metadata["version"] == VERSION
&& metadata["target"] == target
&& metadata["entrypoint"] == layout.executable
&& metadata["resourcesDir"] == "codex-resources"
&& metadata["pathDir"] == "codex-path"
{
Ok(())
} else {
Err(format!("Codex 原生包版本、布局或架构不匹配目标 {target}"))
}
}
#[cfg(test)]
mod tests {
use super::super::codex_bundle::for_target;
use super::*;
#[test]
fn metadata_rejects_version_architecture_and_layout_drift() {
let target = "aarch64-apple-darwin";
let layout = for_target(target).unwrap();
let valid = serde_json::json!({
"layoutVersion": 1,
"version": VERSION,
"target": target,
"entrypoint": "bin/codex",
"resourcesDir": "codex-resources",
"pathDir": "codex-path",
});
assert!(validate_package_metadata(&valid, target, layout).is_ok());
for (key, value) in [
("layoutVersion", serde_json::json!(2)),
("version", serde_json::json!("0.0.0")),
("target", serde_json::json!("x86_64-apple-darwin")),
("entrypoint", serde_json::json!("bin/codex.exe")),
("resourcesDir", serde_json::json!("../private")),
("pathDir", serde_json::json!(null)),
] {
let mut invalid = valid.clone();
invalid[key] = value;
assert!(
validate_package_metadata(&invalid, target, layout).is_err(),
"{key}"
);
}
}
}
@@ -935,11 +935,11 @@ fn render_rust(manifest: &PromptBundleManifest, sections: &BTreeMap<String, Stri
let mut output =
String::from("// @generated by build.rs from prompts/runtime/manifest.json\n\n");
output.push_str(&format!(
"#[cfg(test)]\npub(crate) const RUNTIME_PROMPT_BUNDLE_ID: &str = {};\n",
"pub(crate) const RUNTIME_PROMPT_BUNDLE_ID: &str = {};\n",
rust_literal(&manifest.id)
));
output.push_str(&format!(
"#[cfg(test)]\npub(crate) const RUNTIME_PROMPT_BUNDLE_VERSION: &str = {};\n",
"pub(crate) const RUNTIME_PROMPT_BUNDLE_VERSION: &str = {};\n",
rust_literal(&manifest.version)
));
output.push_str("pub(crate) fn runtime_prompt_bundle_section(id: &str) -> Option<&'static str> {\n match id {\n");
@@ -1,12 +1,11 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "main",
"description": "AI 游戏创作主窗口允许读写系统剪贴板,用于粘贴素材附件和复制生成文件路径;允许弹出原生打开/保存对话框用于素材上传与导出。",
"description": "AI 游戏创作主窗口允许读取系统剪贴板图片,用于粘贴素材附件;允许弹出原生打开/保存对话框用于素材上传与导出。",
"windows": ["client"],
"permissions": [
"clipboard-manager:allow-read-image",
"clipboard-manager:allow-read-text",
"clipboard-manager:allow-write-text",
"core:image:allow-rgba",
"core:image:allow-size",
"core:resources:allow-close",
@@ -1,6 +1,6 @@
共享过程文件(如需维护,请使用这些相对路径):
- project/analysis.md:重要取舍的依据与当前结论。
- project/决策台账.md:待处理事项与下一步,必要时引用相关文档。
- project/dialog.md:仅在用户需要时记录对话摘要或交接信息。
- project/analysis.md
- project/决策台账.md
- project/dialog.md
正式产物使用当前阶段指定的相对路径。
五个策划阶段的审批:当你判断当前策划阶段必需产物已完成时,必须提交阶段审批。用户批准后进入下一阶段。
@@ -1,4 +1,4 @@
概念阶段定稿时,创建或更新 `project/速览卡.md`,简要介绍当前游戏。后续仅在核心体验、范围、平台等概览内容变化时更新,不复制完整决策清单。下面是速览卡的参考结构;根据游戏类型、项目规模和用户要求选择适用字段,同类内容可以合并,复杂项目可以增加必要字段。表格和列表中的示例行按实际对象逐行扩展:
概念阶段定稿时,创建或更新 `project/速览卡.md`。下面是速览卡的参考结构;根据游戏类型、项目规模和用户要求选择适用字段,同类内容可以合并,复杂项目可以增加必要字段。表格和列表中的示例行按实际对象逐行扩展:
# 速览卡:《游戏名》
@@ -1 +1 @@
当前阶段:顶层设计。明确游玩过程、关键规则与反馈、版本范围和验证计划,为系统划分提供依据。
当前阶段:顶层设计。明确玩家持续游玩的循环、资源流、节奏和系统范围。
@@ -1,8 +1,66 @@
# 决策台账:《星露谷物语》示例项目
# 决策台账:《星露谷物语》金样项目
仅列仍需跟进的事项和下一步。详细依据与采用的规则见相关分析和设计文档;事项完成后移出待办。
版本:v3 | 规则:台账放活队列——design 只放结论、分析只放论证、决定与开放问题住这里。编号连续不复用;被推翻的行标 overturned 挂新行,不删行。
状态六态:`confirmed`(用户亲口/亲选)/ `auto_decided`(技术类代决,必带理由+推翻条件,用户一键可翻)/ `default_pending`(默认建议兜底,用户未点头)/ `prototype_pending`(待原型验证)/ `pending_user`(等用户拍板)/ `overturned`(被推翻,挂旧行编号)。
- 体力与战斗是否共享资源:涉及探索压力和恢复规则,结合用户对战斗体验的要求确认,再更新相关系统设计。
- 背包使用格子还是重量限制:在确定存档和界面结构前确认,选择依据记录在分析文档。
- 战斗判定窗口的手感:通过矿井原型试玩观察是否易懂、是否拖慢探索,依据见分析文档“战斗判定窗口是否需要调整”。
- 天气权重是否合适:用前几天的游玩样本检查连续雨天或长期无雨的影响,再调整配置。
> 编号口径:D-01~D-13 与 templates/stardew-analysis.md 台账节选一致(D-04~D-06、D-08~D-10、D-12 原为"就地小权衡,直接登记未开条目",此处按登记口径展开);D-14 起为技术文档期新增,与 stardew-tdd-tech.md 开放问题回执互引。
## 当前待办(活队列)
### 等用户拍板(pending_user)
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|---|---|---|---|---|---|---|
| D-14 | 体力与战斗共享单池 | TDD | user | 风险资源统一制造取舍(概念张力一);**暂按共享实现,改单拆只需改 S02 成本入口** | 战斗参与率实测过低(玩家回避矿井) | pending_user(暂按共享实现) |
| D-15 | 背包格子制 vs 重量制 | TDD | user | 格子制直觉、重量制焦虑感与 T5"休闲不打卡"冲突;暂按格子制实现、存档预留 capacity_type 字段 | 格子管理成为主要负面反馈 | pending_user(B 级阻断存档结构,暂按格子制) |
### 待原型验证(prototype_pending)
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|---|---|---|---|---|---|---|
| D-13b | 战斗判定窗口手感(前摇帧数/无敌帧 450ms 基准) | 系统 | user | 数值可定、手感不可纸面验证 | 原型显示节奏拖慢/玩家困惑 | prototype_pending(规则本体见 D-13 confirmed) |
### 默认建议兜底(default_pending)
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|---|---|---|---|---|---|---|
| D-19 | 天气权重表具体数值(晴/雨/风暴按季节) | TDD | agent | 概念层只定"雨免浇水"定性;数值推内容期填 | 前 5 日出现连续 3 日雨/全无雨 | default_pending(默认值已进数据表,带 designer_note) |
## 已采用决定
### 用户确认(confirmed)
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|---|---|---|---|---|---|---|
| D-01 | 定调:牧场物语系参照、治愈慢节奏 | 概念 | user | 用户原始需求 | — | confirmed |
| D-02 | 单人体验,无多人 | 概念 | user | 概念层非目标 | — | confirmed |
| D-03 | 战斗保持伴生风险,不做装备驱动主轴 | 概念 | user | 概念期问题一 | 矿井流失率过半且归因战斗 | confirmed |
| D-07 | 日目标自设,季节与社区提供低频牵引 | 顶层 | user | 顶层期问题一 | 新手周流失归因无方向 | confirmed |
| D-11 | 采集/钓鱼/战斗统一"活动结果"接口 | 架构 | user | 架构期问题一 | 第三活动类型出现结构性差异 | confirmed |
| D-13 | 战斗采用节奏/指令判定 | 系统 | user | S06 问题一 | 原型显示节奏拖慢/玩家困惑 | confirmed(手感部分拆 D-13b prototype_pending) |
### 技术代决(auto_decided——带理由与推翻条件,用户一键可翻)
| 编号 | 决定 | 层 | 谁 | 依据(理由) | 推翻条件 | 状态 |
|---|---|---|---|---|---|---|
| D-04 | 时间片制:700ms=10 游戏分钟 | 概念 | agent | 原作实证节拍;一天≈14 分钟真实时间贴合 T5"休闲" | 内测一天体感过短/过长 | auto_decided |
| D-05 | 分区域切换(区域独立场景,非连续地图) | 概念 | agent | 概念层"不是什么:无边界开放世界";区域小网络全部步行可达 | 场景切换成为移动负担反馈 | auto_decided |
| D-06 | 28 日/季、四季/年 | 顶层 | agent | 季节窗口制造"本季计划"节奏(支柱二) | 换季频率在测试中被无视 | auto_decided |
| D-09 | 商店营业时段走条件表 | 架构 | agent | 与配方/区域解锁共用 check(condition_id) 单一入口 | 条件表规模膨胀难维护 | auto_decided |
| D-10 | 出货箱日终统一结算 | 架构 | agent | 收入集中进日终面板,强化"一天一结算"叙事;商店现卖保留即时通道 | 玩家普遍绕开出货箱 | auto_decided |
| D-12 | 工具升级期间该工具不可用 | 系统 | agent | 升级=时间成本换效率(顶层张力二);备用旧工具暂不做(开放问题) | 升级期挫败感集中爆发 | auto_decided |
| D-16 | 矿井逐层生成本期不做(P2) | TDD | agent | GDD 已标"不做无限地牢";首期按布局池 8~12 模板拼装 | 内测要求深度爬塔玩法 | auto_decided |
| D-17 | 换装首期 5 层(基础体/裤/衣/发型/饰件),非 19 层 | TDD | agent | 外观自定义非首期卖点;层结构预留到 19 层 | 外观系统成核心诉求 | auto_decided |
| D-18 | 作物品质三档:普通/银/金 | TDD | agent | 经济分层需要(即时变现 vs 等待升值的取舍) | 银金档无人区分、一律普通出售 | auto_decided |
### 已推翻(overturned——旧行保留,挂新行)
| 编号 | 决定 | 层 | 谁 | 依据 | 推翻条件 | 状态 |
|---|---|---|---|---|---|---|
| D-08 | 作物品质两档:普通/银 | TDD | agent | 早期小权衡:两档最简 | — | **overturned → D-18**(经济分层不足,改三档;铱档留 P1) |
## 队列纪律(使用说明)
- 新决定入队:拿下一号(当前最大 D-19,下一号 D-20);就现代决可登记不开条目,但状态必须写 auto_decided 并带理由+推翻条件。
- 用户翻案:旧行标 overturned 挂新行,受影响文档节重写(本台账只记录,不代改)。
- 概念层变更定稿后:速览卡"决定状态与原型验证项"字段随本文件最新版同步。
@@ -1,58 +1,59 @@
# 速览卡:《星露谷物语》金样项目
> 本卡概括当前游戏;仅在核心体验、范围、平台等概览内容变化时更新。具体规则和取舍依据见对应设计与分析文档。
> 字段来源见每节尾注(概念层/定调记录/决策台账)。概念层变更定稿后本卡必须同步更新。
## 1. 游戏名称
《星露谷物语》(金样项目沿用案例名)←概念设计标题
《星露谷物语》(金样项目沿用案例名;新项目由概念层第 1 节定名)←概念层§1
## 2. 一句话描述
继承一座荒废农场的乡村生活 RPG:安排每天的时间与体力,种田、探索、交朋友,把日子过成自己想要的样子。(←概念层「游戏概念」)
继承一座荒废农场的乡村生活 RPG:安排每天的时间与体力,种田、探索、交朋友,把日子过成自己想要的样子。(←概念层§1 一句话概念,45~90 字)
## 3. 游戏分类
乡村生活模拟 RPG(经营+探索+社交;参照系牧场物语)←概念层「游戏概念」
乡村生活模拟 RPG(经营+探索+社交;参照系牧场物语)←概念层§1
## 4. 美术风格(四件)←概念层「身份、基调与世界观」与美术圣经
## 4. 美术风格(四件)←定调记录+概念层§4
- 视觉类型:手绘感像素风、俯视 45° 视角。
- 风格关键词:温暖、田园、四季分明、生活感。
- 色彩与氛围:暖土绿基底+季节信号色整体切换;治愈不压抑;无锐利科技感、无阴暗元素。
- MVP 美术边界:首期 3 区域 tileset、8 位 NPC(行走+立绘)、约 120 物品图标、玩家换装 5 层;不做 19 层全量换装与全区域。
## 5. 游戏支柱(3 条)←概念层「游戏概念」「体验与玩法」
## 5. 游戏支柱(3 条)←设计锚点提炼
| 支柱 | 玩家感受 | 实现机制 |
|---|---|---|
| 自己的节奏 | "今天想干嘛就干嘛,明天一切更顺手。" | 自由日程+时间体力预算;无失败结局 |
| 今天的选择让明天更从容 | "升级工具、攒钱扩建是有意义的。" | 长期投资线:工具升级/技能/设施 |
| 社区让独居变成归属 | "镇上的人在等我。" | NPC 关系/任务/社区修复目标 |
## 6. 核心循环(5 步)←概念层「体验与玩法」
## 6. 核心循环(5 步)←锚点循环位展开
安排一天的时间与体力 → 农/采/钓/矿/战/社交任选组合 → 获得资源·金钱·经验·关系 → 投资工具·设施·种子·物品 → 解锁更高效或更丰富的活动。
## 7. 目标用户 ←概念层「目标玩家与情境」
## 7. 目标用户 ←概念层§5
牧场物语系慢节奏成长玩家+动森式"无压力日常"需求;单人、可反复、每次一至数个游戏日;不要求预先掌握复杂数值。
## 8. 平台事实(禁改)
Web 浏览器运行 · 双视口(桌面/移动)· 键鼠/触屏双输入 · 本地启动后可在浏览器中试玩。
## 9. MVP 系统(本例首期范围)
## 9. MVP 系统(5 个)←概念层"最小闭环粗清单"
| 系统 | 最小功能 | 为什么必须有 | 验证方法 |
|---|---|---|---|
| 时间与日程 | 时钟、天气、日终协调与跨日推进 | 组织日常活动 | 单日行动与多日状态持续一致 |
| 体力与状态 | 行动成本、休息恢复 | 支持日常计划与取舍 | 结合行动调整和玩家反馈判断压力 |
| 农场经营 | 耕种、浇水、生长与收获 | 核心产出与规划场 | 连续数日完成生长、收获与再投资 |
| 探索与地图 | 农场、小镇与基础采集区域 | 支持外出和活动选择 | 移动、出入口与资源点状态正确 |
| 采集与钓鱼 | 本期基础采集,钓鱼后续加入 | 提供农场外的资源来源 | 采集结果正确入账且不重复领取 |
| 物品与制作 | 本期物品身份、背包与工具使用 | 连接活动成果与投资 | 拾取、消耗及存读档结果一致 |
| 成长与技能 | 基础农务或采集成长 | 为后续活动提供目标 | 多日成果产生可理解的能力变化 |
| 经济与商店 | 买种、出售与基础投资 | 连接产出与后续投入 | 收益可用于下一轮活动,具体节奏待验算与试玩 |
| 时间与日程 | 时钟/日终结算/季节天气 | 全局节拍器 | 一个游戏日全流程可完成并结算 |
| 体力与状态 | 单池体力/昏倒惩罚 | 一切取舍的成本源 | 玩家主动在体力耗尽前收手 |
| 农场经营 | 锄种浇收+加工队列 | 核心产出与规划场 | "买种→收获→出售"闭环成立 |
| 物品与制作 | item_id/背包/配方解锁 | 资源身份与转化 | 拾取/堆叠/制作全链无回翻 GDD |
| 经济与商店 | 基准价+价差+出货箱 | 投资回报换算 | 第 4 日现金流回正(前五日验算) |
## 10. 制作边界 ←概念层「边界与约束」
## 10. 制作边界 ←概念层"不是什么"表
不做:硬核生存(无饥饿/债务/死亡惩罚);效率至上的工厂经营;以战斗为核心的动作游戏;剧情驱动的任务链主线;多人竞争;无边界开放世界(区域小网络全步行可达)。
## 11. 创作者提示(本例原型验证安排)
- 先做:单日农务与基础采集,继续数日覆盖作物生长、收获、出售、投资和基础成长,包含必要的 UI 与存读档。
## 11. 创作者提示(先做与验证)←概念层"先做与验证"节
- 先做:第 1 日循环(买种→播种→浇灌→收获→出售→日终结算)+一个可进入的矿井遭遇。
- 暂不做:装备刷取、随机构筑、复杂剧情、节日全量、联机。
- 这样验证:结合试玩观察和玩家对选择理由、后续目标的说明,判断是否形成有意义的计划;同时检查资源与跨日状态的一致性。
- 后续验证:加入一个矿井遭遇,再逐步覆盖关系与社区目标;依据实际问题调整范围,不把能自述计划作为唯一门槛。
- 这样验证:测试者玩完第 1 日后是否主动说"再玩一天";能否说出"明天要先做什么"。
- 达标再扩展:玩家能自述明日计划后,才加社交深度与矿井分层。
## 12. 待原型验证项
- 矿井中的轻度战斗能否提供节奏变化,同时保持探索流畅;通过原型试玩观察判定是否易懂、战斗是否拖慢探索。
## 12. 决定状态与原型验证项(依据决策台账)
- 已确认(confirmed):定调 D-01 / 单人 D-02 / 战斗伴生 D-03 / 日目标自设 D-07 / 活动统一接口 D-11 / 战斗节奏判定 D-13。
- 技术代决(auto_decided,可一键翻案):D-04 时间片 / D-05 分区域切换 / D-06 28 日季 / D-09 营业条件 / D-10 出货箱日终 / D-12 工具占用 / D-16 矿井生成 P2 / D-17 换装 5 层 / D-18 品质三档(推翻 D-08 两档)。
- 等拍板(pending_user):D-14 体力战斗是否共享单池(暂按共享实现);D-15 背包格子/重量(暂按格子制,B 级阻断存档结构)。
- 待原型(prototype_pending):D-13b 战斗判定窗口手感(前摇帧数/450ms 无敌帧基准)。
- 默认兜底(default_pending):D-19 天气权重数值(默认已入表,带 designer_note)。
@@ -1,94 +1,200 @@
# 系统架构:《星露谷物语》
## 系统与职责
## 架构定位与目标
本阶段确定"哪些系统支撑一轮玩法",不展开单系统内部规则。
划分原则:将生活模拟 RPG 拆成职责清晰、可独立讨论的规则系统,同时保留少量跨系统入口,避免"每个功能都能互相调用"造成架构失控。系统划分服务于顶层循环:安排一天、执行活动、获得进展、投入成长、解锁新选择。
架构承接顶层的农场生活体验:安排一天、执行活动、获得进展、投入成长,再形成后续计划。战斗服务于探索中的风险与节奏变化,不作为装备成长主轴。以下系统覆盖完整版本,首个原型只实现其中必要的能力。
一句话架构:
> 玩家在有限的时间与体力下,通过农场、探索与社交三组活动系统产出资源与关系,经物品与经济系统转化为投资,由时间系统推进日终,把一天的成果变成下一天的选择。
| 编号 | 系统 | 职责与权威维护的状态 | 首个原型范围 |
变更记录:
- 2026-09-05:战斗与敌人系统定为伴生风险定位,深度刻意受限,不进入最小闭环核心链(依据:概念分析 D-03)。
## 系统地图
| 编号 | 系统 | 一句话职责 | 优先级 |
|---|---|---|---|
| S01 | 时间与日程 | 时钟、日期、季节、天气,时间通知与日终流程协调 | 基础时间、天气与跨日推进 |
| S02 | 体力与状态 | 体力、恢复、昏倒和状态效果,处理活动提交的成本 | 农务与采集的行动成本、休息恢复 |
| S03 | 农场经营 | 土地、作物、畜牧、设施生产状态与生产规则 | 耕种、浇水、生长与收获 |
| S04 | 探索与地图 | 区域、出入口、角色位置、资源点位置与可用状态,执行移动和区域开放 | 农场、小镇与基础采集区域 |
| S05 | 采集与钓鱼 | 活动判定、获得物与品质规则 | 基础采集;钓鱼后续加入 |
| S06 | 战斗与敌人 | 战斗过程、敌人状态、伤害和战利品请求 | 后续矿井遭遇原型 |
| S07 | 物品、背包与制作 | 物品身份、实例、容器、配方、工具装备及通用制作队列 | 种子、工具、采集物和农产品的持有与使用 |
| S08 | 成长与技能 | 经验、等级、能力与配方解锁条件 | 基础农务或采集成长 |
| S09 | 经济与商店 | 货币、价格、交易、库存及营业条件 | 买种、出售与基础投资 |
| S10 | NPC 与关系 | NPC 日程内容与执行进度、对话、好感和关系事件 | 后续关系原型 |
| S11 | 任务与社区目标 | 任务状态、奖励、社区进度和区域解锁条件 | 后续社区目标原型 |
| S12 | 事件与节日 | 节日内容、触发条件、活动流程与完成状态 | 后续节日内容 |
| S01 | 时间与日程 | 推进游戏时间、日期、季节、天气、营业时间、NPC 日程和日终结算 | P0 |
| S02 | 体力与状态 | 管理体力、负面状态、恢复、昏倒和行动成本 | P0 |
| S03 | 农场经营 | 管理土地、作物、畜牧、农场设施和生产状态 | P0 |
| S04 | 探索与地图 | 管理区域、出入口、可交互资源点、地图解锁和移动 | P0(基础) |
| S05 | 采集与钓鱼 | 管理野外采集、钓鱼活动、资源品质和获得物 | P1 |
| S06 | 战斗与敌人 | 管理矿区或危险区域中的战斗、伤害、敌人行为和战利品 | P1 |
| S07 | 物品、背包与制作 | 管理物品实例、堆叠、工具、装备、配方和制作队列 | P0 |
| S08 | 成长与技能 | 管理技能经验、等级、工具升级、职业选择和能力解锁 | P0(基础) |
| S09 | 经济与商店 | 管理货币、买卖、价格、商店库存、订单和资金流 | P0 |
| S10 | NPC 与关系 | 管理 NPC 日程、对话、好感度、礼物偏好和关系事件 | P1 |
| S11 | 任务与社区目标 | 管理任务状态、阶段目标、奖励、社区修复和区域解锁条件 | P1 |
| S12 | 事件与节日 | 管理季节事件、节日活动、条件触发和特殊奖励 | P1 |
存档保存各系统的持久状态并按归属恢复;UI 与文本呈现展示结果、提供操作入口。它们需要实现规格,但不另行维护玩法规则,规格在 TDD 中展开。
支撑层(不拥有核心规则):
- 存档与进度系统:保存跨日、跨季节和跨阶段的持久状态。
- UI 与文本呈现层:展示状态、提供操作入口、呈现反馈与文本。
容易混淆的边界:
P0 段:
- S01 提供时钟与日期,S10 根据自身日程决定 NPC 的目标和行动,通过 S04 执行移动;S09 判断商店是否营业。时间系统不维护另一套居民日程或商店规则。
- S04 维护资源点的位置和是否仍可采集,S05 判定本次采集的结果;物品入账由 S07 处理,经验由 S08 处理。
- S03 管理农场设施的生产状态,S07 管理背包与通用制作。共用配方时引用同一配方定义,不各自复制材料与产出规则。
- S11 判断社区目标是否满足解锁条件,S04 维护实际开放的区域;S08 管理技能解锁,S07 据此判断配方或工具能否使用。
| 系统 | 目的 | 输入 | 输出 | P0 原因 |
|---|---|---|---|---|
| S01 时间与日程 | 全局时钟与日终 | 各系统行动完成信号、日终触发 | 日期/季节/天气变化、日终结算、跨天 tick | 没有"一天",规划与取舍失去标尺 |
| S02 体力与状态 | 全局行动成本 | 各系统行动请求、食物与休息 | 体力变化、昏倒、状态效果 | 没有它,"想做的事多于做得到的"不成立 |
| S03 农场经营 | 核心产出与规划场 | 时间 tick、种子与工具、体力 | 作物畜产品、设施生产状态 | 概念核心承诺的载体 |
| S04 探索与地图 | 活动场景与空间约束 | 移动指令、区域解锁条件 | 位置、区域状态、资源点入口 | 没有空间结构,农/矿/镇一体失去意义 |
| S07 物品与制作 | 资源身份与转化 | 各系统获得物、配方请求 | 物品实例、制作结果 | 所有系统产出的公共语言 |
| S08 成长与技能 | 长期回报层 | 各活动经验提交 | 等级、能力与配方解锁 | 长期动机的最小载体 |
| S09 经济与商店 | 投资与回报换算 | 物品、金钱 | 价格、交易、库存 | 没有它,"变现 vs 投资"张力无载体 |
## 协作与数据归属
## 系统职责
以下表格描述行动处理和通知,不把所有关系混成同一种依赖箭头。
| 系统 | 主要职责 | 不负责 → 移交谁 |
|---|---|---|
| S01 时间与日程 | 时间推进、日期、季节、天气、营业与日终 | 直接决定某项活动的奖励 → 各活动系统 |
| S02 体力与状态 | 行动消耗、恢复、昏倒、状态效果 | 农作物或敌人的具体配置 → S03/S06 |
| S03 农场经营 | 土地、作物、畜牧、设施生产 | 商店买卖规则和角色技能 → S09/S08 |
| S04 探索与地图 | 区域连接、进入条件、资源点位置、移动 | 具体掉落概率和战斗公式 → S05/S06 |
| S05 采集与钓鱼 | 采集和钓鱼行为、成功条件、获得物 | 物品价格和任务奖励 → S09/S11 |
| S06 战斗与敌人 | 战斗流程、敌人状态、伤害与战利品请求 | 角色长期成长和商店价格 → S08/S09 |
| S07 物品与制作 | 背包、物品、配方、制作与工具装备 | 物品最终经济价值的平衡目标 → S09 |
| S08 成长与技能 | 经验、等级、技能分支、能力解锁 | 单次行动的基础奖励 → 各活动系统 |
| S09 经济与商店 | 货币、交易、库存、订单、价格 | 任务剧情与 NPC 情感变化 → S10/S11 |
| S10 NPC 与关系 | 日程、互动、好感、关系事件 | 全局季节推进和商店库存 → S01/S09 |
| S11 任务与社区 | 目标、前置、奖励、社区进度和解锁 | NPC 的日常行为表现 → S10 |
| S12 事件与节日 | 周期事件、特殊流程和限定内容 | 常规日常行动的基础规则 → 各活动系统 |
| 行动或时机 | 协作与结果归属 |
职责说明:
### S01 时间与日程系统
负责一天制的节奏规则:什么时候推进日期、哪些系统收到跨天 tick、日终结算何时发生。它不负责奖励结算,也不负责作物成长规则——只负责"什么时候"和"谁被通知"。
### S06 战斗与敌人系统
负责战斗内状态、敌人行为与战利品请求。它不直接修改商店价格或 NPC 好感,不负责角色长期成长;战利品只提交请求,由 S07 物品系统入账。定位是矿井探索的风险与节奏变化,不是成长主轴(D-03)。
### S07 物品、背包与制作系统
负责物品身份、容器、堆叠与配方队列。它是全项目的公共语言层——任何系统的产出都以 `item_id` 入账;它不负责物品的经济价值平衡,价格只由 S09 维护。
## 依赖与数据流
```mermaid
flowchart TD
S1[S01 时间与日程] --> S2[S02 体力与状态]
S1 --> S3[S03 农场经营]
S1 --> S4[S04 探索与地图]
S1 --> S10[S10 NPC 与关系]
S1 --> S12[S12 事件与节日]
S3 --> S7[S07 物品与制作]
S4 --> S5[S05 采集与钓鱼]
S4 --> S6[S06 战斗与敌人]
S5 --> S7
S6 --> S7
S7 --> S9[S09 经济与商店]
S7 --> S8[S08 成长与技能]
S8 --> S7
S10 --> S11[S11 任务与社区]
S12 -.读取日期季节.-> S1
UI[UI 与文本呈现] -.读取状态.-> S1
UI -.读取状态.-> S3
UI -.读取状态.-> S7
SAVE[存档与进度] -.订阅持久状态.-> S1
```
```mermaid
flowchart LR
T[时间/体力] --> ACT[玩家行动]
ACT --> GAIN[物品·金钱·经验·关系·任务进度]
GAIN --> INV[制作·交易·升级·解锁]
INV --> NEW[新的行动选择]
NEW --> ACT
```
主要状态:
- 全局状态:日期、季节、天气、当前时间、已解锁区域、社区进度。
- 玩家状态:位置、体力、生命、技能等级、工具、装备、背包和金钱。
- 场景状态:土地、作物成长、设施生产、资源点、敌人和宝箱。
- 社会状态:NPC 位置、关系值、已触发事件、任务阶段和节日参与状态。
主数据归属规则:
- 规则文档描述"如何计算"和"何时发生";数据表描述"有哪些对象"和"每个对象的配置"。
- 系统之间通过稳定 ID 关联(物品 ID、NPC ID、区域 ID、任务 ID、配方 ID)。
- 任何系统都不复制另一系统的主数据;任务只引用物品 ID,不重新定义物品价格。
## 核心循环覆盖检查
| 顶层循环环节 | 认领系统 |
|---|---|
| 播种与农务 | S03 检查地块及行动条件,S07 检查种子或工具,S02 检查行动成本;确认可执行后更新各自状态。失败时不留下仅扣种子或体力的部分结果 |
| 采集 | S04 确认资源点可用,S05 判定获得物,S07 入账,S08 接收活动经验;成功后由 S04 更新资源点状态 |
| 出售与购买 | S09 校验营业、库存与价格,S07 校验物品和容器;交易成功时双方分别更新所拥有的状态,失败时保持原状态 |
| 成长与解锁 | 活动系统报告成果,S08 更新经验与能力;S07 等使用方读取解锁结果,不自行维护另一套技能进度 |
| 日终 | S01 停止当日行动并协调结算;S03 推进作物与生产、S09 结算出货、S08 结算成长,之后汇总反馈并保存。跨日通知让各系统准备次日状态 |
| 居民行动与节日 | S10、S12 读取 S01 的日期与时间,按各自规则决定活动;需要移动时交给 S04,不反过来推进全局时钟 |
| 查看天气、日程与目标 | S01、S11、S12、UI |
| 选择活动并移动 | S04、S02 |
| 农务与生产 | S03、S07、S02 |
| 采集、钓鱼与战斗 | S04、S05、S06、S07 |
| 出售、购买与投资 | S09、S07、S03 |
| 社交与委托 | S10、S11、S07 |
| 日终结算与保存 | S01、S12、存档、UI |
跨系统行动的提交方式、失败处理和精确结算顺序在系统文档与 TDD 中展开,须满足上述结果一致性。日终保存应包含已经完成的结算,不能读档后重复发放同一次收益。
## 目录映射
系统通过 `item_id`、`npc_id`、`region_id`、`recipe_id` 等稳定标识关联。物品身份与实例归 S07,价格归 S09,关系值归 S10;任务、界面和存档可以引用或展示这些结果,不独立修改对应事实。UI 从权威状态刷新,只读展示副本不承担结算;存档快照在结算完成后生成,读档时恢复到对应系统。
跨系统共享的约束:
- 时间与生产使用一致的游戏时间单位,行动成本、制作时长与跨日成长须说明对应关系。顶层暂定常规游戏日约 10~20 分钟,实际换算与暂停规则在后续规格中明确并试玩验证。
- 金钱由 S09 统一结算,各活动提供产物或交易请求;经验是持续积累的进展,不作为货币消费。
- 失败后果按顶层场景分别处理:矿井倒下可能损失部分钱物,换季可能使作物枯萎,同时保留大部分长期进展。涉及体力、物品、金钱或位置的变化由各自负责系统执行。
- 存档、UI 和活动系统使用相同的状态含义,避免显示已获得但实际未入账、或已结算却未保存的结果。
## 系统文档映射
本例分别展开各系统,以下是策划工作区的文档目录;实现代码如何拆模块由 TDD 决定。
| 系统 | 文档目录 |
| 目录 | 本阶段定位 |
|---|---|
| S01 时间与日程 | `project/03_systems/S01_time_schedule/` |
| S02 体力与状态 | `project/03_systems/S02_stamina_status/` |
| S03 农场经营 | `project/03_systems/S03_farm_management/` |
| S04 探索与地图 | `project/03_systems/S04_exploration_map/` |
| S05 采集与钓鱼 | `project/03_systems/S05_foraging_fishing/` |
| S06 战斗与敌人 | `project/03_systems/S06_combat_enemies/` |
| S07 物品、背包与制作 | `project/03_systems/S07_items_inventory_crafting/` |
| S08 成长与技能 | `project/03_systems/S08_progression_skills/` |
| S09 经济与商店 | `project/03_systems/S09_economy_shop/` |
| S10 NPC 与关系 | `project/03_systems/S10_npc_relationship/` |
| S11 任务与社区目标 | `project/03_systems/S11_quests_community/` |
| S12 事件与节日 | `project/03_systems/S12_events_festivals/` |
| 03_systems/S01_time_schedule/ | 时间推进、日期季节天气、营业时段、日终结算 |
| 03_systems/S02_stamina_status/ | 体力、状态效果、昏倒与恢复 |
| 03_systems/S03_farm_management/ | 土地、作物、畜牧、设施生产 |
| 03_systems/S04_exploration_map/ | 区域、连接、资源点、解锁与移动 |
| 03_systems/S05_foraging_fishing/ | 采集、钓鱼、品质与获得物 |
| 03_systems/S06_combat_enemies/ | 战斗、敌人行为、伤害与战利品请求 |
| 03_systems/S07_items_inventory_crafting/ | 物品、背包、配方与制作队列 |
| 03_systems/S08_progression_skills/ | 技能经验、等级、工具升级、能力解锁 |
| 03_systems/S09_economy_shop/ | 货币、买卖、价格、库存与订单 |
| 03_systems/S10_npc_relationship/ | NPC 日程、对话、好感与关系事件 |
| 03_systems/S11_quests_community/ | 任务、社区目标、奖励与解锁条件 |
| 03_systems/S12_events_festivals/ | 季节事件、节日、条件触发 |
| 支撑层不单开系统文档 | 存档与 UI 随实现层组织,规则不独立成文 |
## 实现范围与验证
## MVP 最小闭环
1. 玩家在一个游戏日内完成开垦、播种、浇灌,并看到成长状态反馈。
2. 在时间与体力约束下选择当日主目标(农场劳动或外出)。
3. 外出采集(或矿井轻度战斗)带回资源。
4. 通过出售或加工获得金钱,投资种子或工具。
5. 日终结算展示当日变化并保存。
6. 次日作物状态变化,玩家据此形成新计划。
7. 数个游戏日内出现第一次技能提升与配方解锁。
首个原型包含 S01、S02、S03、S04、S05、S07、S08、S09 的上述基础能力,加上必要的 UI 与存读档。完整版本还需展开钓鱼、制作、畜牧、战斗、居民关系、社区目标与节日等能力;完整清单不等于首个原型的施工范围。
如果这条闭环不成立,不应继续增加钓鱼深度、节日、社区目标或更多区域。
首个流程从查看天气和选择目标开始,经农务或外出采集获得进展,再通过出售、购买和日终进入下一天。单日用于观察计划与取舍;连续数日用于覆盖作物生长、收获、投资和基础成长,不要求作物一天内完成播种到收获。
## 统一数值基准
本案例采用"宽松治愈型"数值风格。全局单位:时间片、游戏日、货币、体力、经验;所有数值字段必须注明单位。
- 时间节奏基准:单次常规行动控制在短时间片内;玩家一天应能完成农务、一个主要外出目标和少量顺路活动;早期玩家不应因一次路线失误失去整天进度。
- 货币量级基准:主要货币只有一种;初期基础种子可用少量日常产出购买;一次普通收获不应立刻买下最高阶升级;任务奖励以补足短期资金为主,不替代生产交易。
- 成长回报基准:前几级在正常尝试一种活动的数个游戏日内出现;升级奖励优先采用节省时间体力、扩大选择和解锁配方,而非单纯提高伤害售价;专长分支宽松可恢复。
- 体力与风险基准:体力是规划提示不是严苛倒计时;普通农务与移动成本低,战斗、钓鱼和重型工具才产生明显取舍;失败成本采用时间、少量金钱或位置变化,不损毁进度。
| 验证问题 | 内容与判断依据 |
(具体换算数值与前五日验算由技术文档层·数值策划承接。)
## 系统边界
- 农场经营只管理农场内的生产状态,不负责所有资源的通用背包逻辑。
- 探索与地图只管理"在哪里"和"能否进入",不管理每种活动的具体奖励。
- 战斗只管理战斗内状态和战利品请求,不直接修改商店价格或 NPC 好感。
- NPC 与关系负责互动和关系变化;任务与社区负责可验证目标,二者通过事件和条件连接。
- UI、文本和表现不反向承载核心规则;所有关键变化必须由规则系统确认。
- 本案例不拆出独立多人、拍卖、复杂天气模拟、动态市场或高复杂度叙事工具系统。
## 优先级与范围
- P0(最小可玩闭环):时间与日程、体力、农场、物品背包、经济、基础地图、基础成长和日终结算。
- P1(形成完整案例):采集、钓鱼、轻度战斗、NPC 关系、任务、社区目标、制作、商店、季节和节日。
- P2(扩展内容):更多区域、敌人、作物、配方、关系事件、节日小游戏和终局后的自由活动。
拆分系统不等于所有系统都要在最小版本同时实现;系统独立性是为了便于协作和后续裁剪。
## 风险与校验
| 风险 | 校验方式 |
|---|---|
| 基础系统是否共同支持日常计划 | 试玩农务与采集,观察时间、体力、物品和金钱变化是否一致,结合玩家说明判断选择是否有意义 |
| 跨日成果能否支持后续计划 | 连续游玩并存读档,检查作物、交易与成长是否持续且无重复结算,结合玩家反馈判断是否形成新的目标 |
| 战斗是否改善探索节奏 | 后续加入 S06 与矿井所需的地图、状态和物品能力,观察战斗理解、损失恢复及其对日常活动的影响 |
| 关系与社区是否形成长期目标 | 后续加入 S10、S11 及对应内容,观察多日投入与目标选择;单日原型不据此判断长期体验 |
| 农场变成例行公事,失去规划感 | 玩家是否在目标选择阶段出现真实取舍与计划调整 |
| 矿井战斗反客为主 | 战斗收益是否仍以"农场难以产出的材料"为主,而非直接金钱 |
| 时间压力变成打卡义务 | 休闲型玩家能否自由调低日程重量而不被惩罚 |
| 经济成长过快,后期失去决策 | 升级价格是否持续制造"效率 vs 规模"的选择 |
| UI 泄题,探索失去意义 | 关键信息是否保留为探索发现而非全量直读 |
| 系统间主数据重复维护 | 交叉检查:同一事实是否只有一个系统拥有写权 |
以上是验证计划,尚未形成试玩结论。出现问题时先判断是玩法目标不成立、协作职责遗漏还是实现错误,再调整相应设计与范围。
## 风险与未决问题
- 时间、体力和收益可能共同把休闲生活变成赶任务:沿用顶层验证计划,比较不同玩家的计划调整与压力反馈。
- 农场生产、制作和交易可能重复消费或入账:在系统规格中明确提交与失败处理,在实现阶段验证中断和日终存读档后的结果。
- 社区目标采用章节、可选收集还是组合仍需展开:在该内容进入实现范围前确定,并补齐 S11 与 S04 的解锁协作。
- 体力与战斗生命是否共享、战斗最低深度如何确定:不阻塞基础日常原型,在战斗原型前解决,再补齐 S02、S06 及相关 TDD 规格。
## 开放的结构问题
- 体力与生命是否保持为两个状态,还是在轻度战斗中共享一套风险资源?
- NPC 日程、任务条件和节日事件之间采用统一条件格式还是各自维护?
- 农场设施生产是否由农场系统统一管理,还是交给通用制作队列?
- 采集、钓鱼和战斗是否共享统一的"活动结果"接口?
- 哪些系统需要独立数据表,哪些小型配置应合并为一张内容表?
@@ -1,43 +1,63 @@
# 概念设计:《星露谷物语》
## 游戏概念
## 一句话概念
《星露谷物语》是一款以经营农场为基础、融合探索、采集、制作、轻度战斗、角色成长与社区叙事的乡村生活模拟 RPG;玩家通过安排每日时间与体力,把荒废农场逐步建设成理想家园,并与周围居民建立关系。
《星露谷物语》是一款以经营农场为基础、融合探索、采集、制作、轻度战斗、角色成长与社区叙事的乡村生活模拟 RPG。玩家安排每日时间与体力,把荒废农场逐步建设成理想家园,并与周围居民建立关系。吸引力在于按自己的节奏塑造生活:今天的选择让明天更从容,社区关系让独居逐渐变成归属。
## 定调与设计锚点
## 体验与玩法
### 定调记录
- 参照选择:以牧场物语系为主(无压力日常方面学动物森友会);不参考任何高难动作与生存类游戏。
- 调性滑杆:压力感 低 / 战斗比重 低 / 管理深度 中 / 叙事比重 中低 / 节奏 慢。
- 调性锚:
T1 轻松治愈、自己的节奏(目标体验);T2 不劝退、无唯一最优解(体验门槛);T3 战斗轻度、非高难动作(非目标);T4 以"游戏日"为单位、可反复的单人体验(情境);T5 时间体力有限但休闲不打卡(跑偏风险);T6 小团队可维护的规模(关键约束);T7 日常叙事而非宏大主线,隐藏信息不迫使玩家查攻略(非目标/跑偏风险)。
玩家通过改善农场、发现资源与区域、提升技能、完成社区目标和发展人际关系,获得自由规划、持续成长与发现秘密的乐趣。既可以追求效率,也可以把时间用于装饰、社交或探索。
### 设计锚点
- 核心幻想:离开令人疲惫的城市生活,继承一片荒废土地,在自己的节奏中经营、探索、成长,并成为社区的一员。
玩家念头:"再玩一天就好——今天做完想做的事,明天的一切都会更顺手。"
- 目标体验:治愈、自由规划、持续成长、发现秘密,以及"今天的选择会让未来更轻松"的掌控感。
- 玩家动机:改善农场与生活条件;发现新区域和资源;完成社区目标;提升技能;与 NPC 建立关系;按照自己的偏好塑造生活方式。
- 核心循环:安排一天的时间与体力 → 进行农业、采集、钓鱼、采矿、战斗或社交 → 获得资源、金钱、经验与关系进展 → 投资工具、设施、种子和物品 → 解锁更高效或更丰富的活动。
- 跑偏风险:系统过多导致目标分散;时间与体力限制把休闲体验变成每日打卡;隐藏信息迫使玩家依赖外部攻略;经济成长过快使后期失去决策。
- 非目标:不做多人竞争、高难度动作战斗、唯一最优效率经营、主线剧情取代日常(详见《不是什么》)。
主要游玩过程是:安排一天的时间与体力 → 进行农业、采集、钓鱼、采矿、战斗或社交 → 获得资源、金钱、经验与关系进展 → 投资工具、设施、种子和物品 → 解锁更高效或更丰富的活动,在下一天重新安排计划。
## 玩家身份与基调
- 玩家身份:一名辞职逃离城市、继承祖父荒废农场的归乡人——不是拯救世界的英雄,是重新学会生活的人。季节与节日构成一年的节拍,日落结算构成每天的呼吸。
- 情绪基调:温暖治愈,慢而踏实。可以有忙碌与轻度压力(时间、体力),不做生存焦虑(饥饿、债务倒计时)与黑暗题材;孤独感只作为被社区逐渐治愈的起点,不成为基调本身。
其中的重要取舍包括:
- 时间与体力有限,玩家需要安排今天的优先级,做一件事意味着少做另一些事。
- 出售资源能立即获得资金,保留资源制作设备和升级工具则能提高未来效率。
- 农场提供可预测的收益;探索可能带来新资源和发现,也会消耗时间、承担风险。
- 赚钱占用社交时间;发展关系会减缓眼前收入增长,但能带来配方、剧情和情感回报。
- 季节、节日和社区目标提供方向;追赶这些目标会占用自由安排日常的空间,错过部分机会则需要等待或调整计划。
## 身份、基调与世界观
玩家是一名辞职离开城市、继承祖父荒废农场的归乡人,在经营与探索中重新建立生活,并成为社区的一员。日落结算构成每天的节拍,季节与节日带来更长周期的变化。
情绪基调温暖治愈,节奏慢而踏实。时间与体力可以带来忙碌和轻度压力,但不以饥饿、债务倒计时或黑暗题材制造生存焦虑;孤独感是逐渐融入社区的起点。
视觉采用复古像素风的温暖乡村。农场、商店、社区设施、自然区域和矿井组成可步行抵达的生活网络。季节、天气、节日、居民日程和区域变化让同一张地图产生生活感;叙事通过日常对话、关系事件、任务和社区目标展开。
参照牧场物语系的农场生活组织方式,以及动物森友会的自定义、装饰和按自己节奏整理日常的体验;农业经营中的时间、体力、季节取舍与社区修复仍是本例的重要内容。参照用于说明体验,不复制具体角色、文本、美术、地图或数值。
## 风格与世界观
复古像素风的温暖乡村世界。玩家来到一个正在现代化与传统生活之间摇摆的小镇,农场、商店、社区设施、自然区域和矿井共同构成可步行抵达的生活网络。世界观服务于生活模拟而非复杂设定解释:季节、天气、节日、居民日程和区域变化,让同一张地图随着时间产生生活感。叙事主要通过 NPC 日常对话、关系事件、任务和社区目标逐步展开。
## 目标玩家与情境
- 目标玩家:与牧场物语系受众高度重合——喜欢种田与小人际的慢节奏成长玩家;同时吸收动物森友会式"无压力日常整理"的需求(自定义、装饰、按自己的节奏玩)。但它不能变成纯装饰沙盒,因为农场经营的时间、体力与季节取舍,以及社区修复目标必须始终存在。
- 适合情境:单人、可反复游玩、每次一个游戏日或几个游戏日;可以高效规划,也可以把时间用于装饰、社交或探索。
- 体验门槛:需要理解基础资源转换和时间安排,不应要求预先掌握复杂数值或寻找唯一正确答案。
面向喜欢种田、人际关系与慢节奏成长的玩家,也容纳偏好装饰、收集和自由安排日常的玩家。
## 不是什么
| 不是 | 因为 |
|---|---|
| 硬核生存农场模拟 | 没有饥饿、债务、死亡惩罚;压力止于温和的时间与体力 |
| 效率至上的工厂经营 | 不要求唯一最优解,装饰与闲逛是合法玩法而非浪费 |
| 以战斗为核心的动作游戏 | 战斗只是采矿与探索的伴生风险,深度刻意受限 |
| 剧情驱动的叙事游戏 | 社区叙事是日常的背景与情感回报,不是任务链主线 |
| 多人社交平台 | 单人体验为前提,人际关系由 NPC 关系承载 |
| 无边界开放世界 | 地图是功能明确的小区域网络,全部可步行抵达 |
本例围绕可反复游玩的单人体验,每次可玩一个或几个游戏日。玩家需要理解基础资源转换和时间安排,不应依赖复杂数值计算或寻找唯一正确答案才能推进。
## 核心张力
- 时间与体力有限,但想做的事情很多:玩家必须决定今天的优先级。
- 立即变现与长期投资:出售资源能快速获得资金,制作设备和升级工具则能提高未来效率。
- 稳定经营与未知探索:农场提供可预测收益,矿井、钓鱼和新区域提供风险与发现。
- 个人效率与社区关系:把时间用于赚钱会挤压社交,但关系又会带来配方、剧情和新的情感目标。
- 自由生活与阶段目标:玩家可以自由安排日常,同时受到季节、节日、任务和社区修复目标的轻度牵引。
## 边界与约束
- 概念层只定义核心幻想、目标用户、体验基调与排除方向;具体战斗公式、作物成长天数、礼物偏好、掉落率、系统清单和 MVP 内容,留给顶层及以后决定。
- 设计规模以单人或小团队可理解、可维护为前提;地图采用多个功能明确的区域,而非无边界开放世界。
- 所有系统都必须回流到"安排一天并获得长期改善"的核心循环;独立小游戏或装饰功能不能成为主要范围扩张来源。
- 案例声明:本文以《星露谷物语》为案例展示设计的组织方式,不复制其具体角色、文本、美术、地图或数值。
- 战斗服务于采矿与探索,不扩展为高难度动作游戏;社区叙事提供日常背景与情感回报,不用宏大主线取代农场生活。
- 时间和体力形成温和的取舍,避免把休闲变成每日打卡。装饰、闲逛和社交都有价值,不以唯一最优效率为目标。
- 本例按单人或小团队规模控制内容,地图采用功能明确的小区域网络,不扩展为无边界开放世界或多人社交平台。
- 各系统服务于日常生活及其长期改善。独立小游戏或装饰内容的扩张不能挤占核心体验;同时避免经济成长过快使后期失去选择,或隐藏信息迫使玩家依赖攻略。
- 后续设计应允许效率型和休闲型玩家按自己的偏好成长;具体系统范围、版本内容、战斗公式、作物成长天数和掉落率等再逐步展开。
## 概念定稿
《星露谷物语》的核心不是"种田赚钱",而是:
> 在自己的节奏里经营一片土地与一段生活——今天的选择让明天更从容,而社区让独居变成归属。
交给下一层的约束:时间与体力必须构成温和而非焦虑的取舍;战斗、采矿、社交等支线必须回流农场生活循环;成长权重要允许玩家自定义(效率型与休闲型玩家都成立)。
(调性已在第 2 节定死;顶层及以下一切开放问题先回定调记录的 T1~T7 级联。)
@@ -1,56 +1,120 @@
# 战斗与敌人系统:S06
版本:v2
## 系统目的
为危险区域提供轻度、可理解的战斗挑战,使玩家在探索中承担风险,并通过装备、补给和技能成长验证长期准备。战斗是生活模拟循环的支柱之一,不是游戏的唯一核心。
## 职责与原型范围
## 支撑的玩家体验
- 玩家能观察敌人行为,选择攻击、躲避、补给或撤退。
- 战斗结果主要取决于准备、判断和适度操作,而不是高强度连招。
- 深入危险区域会带来更高资源和成长回报,也会增加生命、时间和补给压力。
- 失败有明确原因和可恢复成本,不应摧毁长期农场进度。
战斗服务于矿井探索中的风险与节奏变化,不扩展为高难度动作或装备构筑主轴。S06 负责敌人行为、攻击与伤害判定、战斗结果和战利品请求;通过 S02、S04、S07、S08 等系统完成玩家状态、位置、物品和经验更新。
## 进入与退出
### 进入
- 玩家进入允许战斗的危险区域或触发敌人遭遇。
- 检查区域、时间、装备、生命、背包和任务条件。
- 初始化当前战斗区域、敌人组合、战斗状态和可撤退条件。
### 退出
- 击败敌人并完成战斗奖励结算。
- 玩家主动撤退或离开战斗区域。
- 玩家生命归零,由体力与状态系统执行昏倒或失败惩罚。
- 特殊事件、日终或区域状态强制结束战斗。
战斗不属于首个日常原型。后续矿井原型暂按实时操作展开,先验证移动避让、普通攻击、补给与撤退;重攻击、独立闪避或格挡技能、首领等内容暂未纳入。以下是供验证的方案,尚未形成试玩结论;生命与体力关系、具体判定参数等缺口需在战斗进入施工范围前补齐。
## 玩家行动
- 移动、观察敌人攻击范围和行为状态。
- 普通攻击、重攻击或使用装备技能。
- 防御、闪避、格挡或利用场景短暂规避伤害。
- 使用食物、药剂等消耗品。
- 拾取战利品、调查宝箱或选择继续深入。
- 在满足条件时撤退,保留已结算的奖励。
## 遭遇与行动
通用流程:
`进入遭遇 → 读取敌人状态 → 玩家行动 → 敌人响应 → 结算伤害/效果 → 判断胜负或撤退`
玩家经 S04 进入可战斗区域,S06 根据该区域的遭遇配置和已有敌人状态建立遭遇。进入区域本身不消费补给或发放奖励;消耗发生在实际行动成功时。
## 取舍表
玩家观察敌人位置与攻击准备,选择接近攻击、移动避让、使用补给或沿可用出口撤退。普通攻击先检查武器、距离、方向和动作间隔,再按命中规则结算;攻击范围、伤害计算与动作间隔的具体定义尚待补齐。补给的持有和消耗由 S07 处理,恢复效果交 S02 更新,使用失败不能只扣除物品。
| 决策 | 立即收益 | 延迟收益 | 主要代价 |
|---|---|---|---|
| 继续深入还是安全撤退 | 更多资源 | 更高风险与返程压力 | 已得战利品可能损失 |
| 消耗品现在用还是留着 | 维持当前探索 | 应对更强敌人 | 局部战况恶化 |
| 快速击败还是稳健闪避 | 节省时间 | 降低受伤风险 | 补给与时间消耗 |
| 高伤高耗装备还是基础攻击 | 更快击杀 | 稳定与低消耗 | 资源消耗大 |
| 资金投武器防具还是农场设施 | 战斗能力 | 农场产能 | 另一侧进度放缓 |
击败一个敌人后可继续探索,不自动结束区域活动。沿出口离开时保留已入账的物品与经验;玩家倒下时进入失败处理,不能按安全撤退结算。日终等中断与伤害、拾取同时发生时的处理顺序,需要在矿井原型前明确。
## 状态与规则
### 玩家战斗状态
- 当前生命、最大生命和状态效果。
- 装备中的武器、防具、饰品和消耗品。
- 攻击、防御、移动、闪避和技能冷却状态。
- 当前战斗区域、遭遇编号和撤退状态。
### 敌人状态
敌人状态至少包括待机、警觉、攻击前摇、攻击中、受击、眩晕、死亡和撤退。
每个敌人的实例数据(生命、位置、目标、状态效果、掉落引用)的字段定义由技术文档层承接。
### 战斗规则
- 只有满足攻击距离、方向、冷却和装备条件时,攻击才可结算。
- 伤害由攻击来源属性、目标防御、技能倍率和状态效果共同决定。
- 敌人攻击必须有可识别的前摇或预警,给予玩家反应与撤退机会。
- 生命降至零时进入死亡或昏倒状态;具体惩罚由体力与状态系统处理。
- 敌人死亡后只结算一次经验与战利品,并写入遭遇状态,避免重复领取。
- 撤退后已完成的战斗奖励保留,未击败敌人按区域刷新规则处理。
### 区域遭遇
- 危险区域由敌人组、刷新规则、深度或阶段配置组成。
- 进入更深区域可以提高敌人强度、资源价值和特殊遭遇概率。
- 区域难度应通过可理解的装备、区域和任务条件表达,不依赖突然的数值墙。
- 宝箱、精英敌人和首领可作为独立遭遇类型,但不在最小版本中同时扩张。
## 敌人行为与结果
## 数值与数据交接(→技术文档层)
本系统交由技术文档层(数值策划)定义的数据类别:敌人配置、敌人行为配置、武器配置、技能配置、遭遇配置、战利品配置、状态效果配置。
本原型以能接近玩家并进行近身攻击的普通敌人为起点:发现玩家后接近,进入攻击距离后给出可识别的准备动作,再执行攻击并恢复。失去目标后的行为、受击是否打断、离开区域后的恢复方式还需补齐;不为所有敌人预设眩晕、撤退等完整状态集合。
随交接附下的设计侧定性约束:
- 敌人数据拆分为"是什么 / 怎么行动 / 掉什么"三类,使难度与经济可独立调节。
- 普通敌人不应稳定掉落大量高价值物品;战斗收益主要由矿物、经验和区域发现组成。
- 稀有材料是"有明确用途的探索奖励",但必须保留任务、宝箱等补充渠道,避免战斗失败后无法推进。
- 基础战斗允许玩家一日内完成少量遭遇并安全返程,不要求连续刷怪。
- 失败保留已结算的普通战利品,主要损失是时间、位置或少量金钱,不清空背包。
- 自动化收益节省日常体力,但不能让玩家跳过农场维护的全部决策。
- 收益回流方向:区域 → 敌人 → 材料 → 加工 → 农场自动化;战斗不直接取代农场收入。
攻击准备应让玩家看懂危险并有机会应对,实际时长和表现通过试玩调整。伤害只在有效命中时结算,不能因动画或反馈重复播放而多次扣除。敌人被击败后停止行动,并为该次击败结算一次战利品和经验;拾取或存读档不能再次领取同一次奖励。
## 反馈
- 攻击命中、受击、闪避、格挡和暴击提供清晰的视觉与声音反馈。
- 敌人显示生命、预警、当前状态和可攻击时机。
- 玩家生命、补给、冷却和撤退可用性持续可见。
- 战斗胜利显示经验、战利品和区域进度。
- 失败说明主要原因,并明确损失、保留内容和可恢复路径。
继续深入可以获得更多资源和经验,也会消耗时间、生命或补给并增加倒下风险;提前撤退保留当前收获,但放弃本次继续探索的机会。矿井中倒下沿用顶层设计:损失部分金钱或物品,保留大部分长期积累,补充准备后可以再次探索。具体损失范围和幅度尚未确定,不承诺所有已入账战利品都免于失败损失。
## 内部循环
### 单次战斗循环
`观察敌人 → 选择攻击或防御 → 处理敌人响应 → 造成或承受伤害 → 调整策略 → 击败或撤退`
### 危险区域循环
`准备装备与补给 → 进入区域 → 战斗与搜刮 → 判断继续深入或返程 → 带回资源 → 升级能力`
### 长期循环
`获得战斗经验与装备 → 提升生存能力 → 挑战更深区域 → 获得稀有资源 → 解锁新制作、任务或地图`
战斗收益服务于本例的探索与生活成长,具体掉落和经济关系结合物品用途及收益平衡确定;本例的取向不作为其他游戏的通用战斗限制。
## 输入、输出与依赖
### 输入
- 探索与地图系统提供战斗区域、位置和遭遇入口。
- 时间系统提供当前时间、季节和日终信号。
- 体力与状态系统提供生命、体力、状态效果和失败处理。
- 物品系统提供武器、防具、消耗品和战利品接收入口。
- 成长系统提供属性、技能和装备解锁。
- 玩家通过核心玩法系统提交战斗行动。
### 输出
- 向物品系统提交战利品和消耗品变化。
- 向成长系统提交战斗经验和能力进度。
- 向地图系统提交敌人、宝箱和遭遇状态。
- 向任务与社区系统提交击败、调查和区域进度。
- 向 UI 输出战斗状态、反馈、胜负和撤退结果。
## 协作与数据归属
## 边界与非目标
- 不负责通用生命与昏倒惩罚,只提交状态变化。
- 不负责武器物品的背包、耐久和售价主数据。
- 不负责字段定义、数值配置与表格结构——归技术文档层(数值策划)。
- 不做高难度动作连招、复杂多人战斗或精确帧竞速。
- 不让战斗成为获得普通农场资源的唯一方式。
- 不在本系统中定义全部敌人、武器和首领内容。
| 内容 | 负责方与协作 |
|---|---|
| 敌人行为、战斗判定和击败记录 | S06 维护;通过 S04 执行位置变化,使用实际位置进行判定 |
| 玩家生命、体力、状态效果和倒下处理 | S02 接收 S06 的伤害或成本请求,协调失败后果;生命是否与体力共池尚待明确 |
| 区域、出入口与角色位置 | S04 提供,S06 据此判断遭遇和撤退;敌人刷新条件由 S06 与区域生命周期衔接 |
| 武器、补给、战利品身份和持有 | S07 维护;S06 引用物品标识与已确定的战斗属性,提交消耗或获得请求 |
| 战斗经验与能力 | S08 接收击败结果并更新经验;S06 使用已生效的能力结果 |
| 失败损失与时间 | S09 更新金钱,S07 更新物品,S04 更新位置;S01 提供时间及日终通知,各系统按明确的失败或中断结果更新 |
| 任务进度与呈现 | S11 接收相关击败结果;UI 展示权威状态、接受操作请求,不自行判定伤害或发奖 |
物品入账失败时,待领取奖励如何保留、离开区域后能否再取,需在矿井原型前确定。存档保存敌人、奖励与各系统已完成的结果,恢复后不得重复发奖。具体更新顺序、持久化与恢复协议由 TDD 落实。
实现所需的数据包括敌人行为与属性、攻击判定、区域遭遇、物品引用、奖励和失败后果。已确定的规则与参数保留在设计中,由 TDD 收编并补齐字段、配置、计算方式和默认值,不仅交接数据类别名称。
## 反馈与验证
玩家应能识别敌人的攻击准备、命中或受伤结果、当前生存状态与补给使用结果。无法攻击、使用物品或撤退时说明当前原因;倒下后说明损失、保留内容和返回位置。
| 场景 | 判断依据 |
|---|---|
| 遭遇普通敌人并攻击或避让 | 玩家能理解攻击准备,伤害与实际命中一致;结合试玩反馈判断操作压力是否符合轻度战斗定位 |
| 击败、拾取并存读档 | 物品与经验正确入账,同一次击败不会重复结算;入账受阻时按补齐后的奖励保留规则处理 |
| 安全撤退与矿井倒下 | 撤退保留已入账成果;倒下执行明确的部分损失,提示与各系统实际结果一致 |
| 使用补给或遭遇日终中断 | 物品与恢复结果一致,中断按补齐后的顺序结束处理,不留下部分扣除或重复收益 |
以上为待执行的验证场景。战斗进入实现范围前,还需明确生命与体力关系、敌人行为与刷新、伤害和动作参数、奖励入账受阻处理、失败损失及日终中断顺序,并同步 S02、S04、S07、S08、S09 和相应 TDD。
## 开放问题
- 战斗采用实时操作,还是更简化的节奏/指令判定?
- 体力是否影响攻击与闪避,还是只影响探索和农务?
- 武器是否有耐久度,还是通过升级与装备更换形成消耗?
- 战斗失败的主要成本采用金钱、位置、时间,还是有限组合?
@@ -1,64 +1,82 @@
# 美术圣经:《星露谷物语》首个日常原型(TDD 示例)
# 美术圣经:《星露谷物语》(TDD 金样 · 美术圣经)
## 范围与设计依据
> 状态:reviewed | 定调锚:概念层@v1 第 2 节(定调记录:牧场物语系参照、压力低/节奏慢/治愈) | style_id:`stardew_warm_rural_pixel`
> 实证规格来源:星露谷 1.6.15 解包知识库 v3(资产计数时点 2026-09-11,快照 stardew-1.6.15-7f1e5b8e)。写新项目时按本项目定调重译,数字仅作规模参照。
本例只覆盖首个日常原型:农场、小镇、基础采集区域;耕地、播种、浇水、跨日生长、收获、买种、出售,以及时间、天气、体力、背包、金钱和日终反馈。它承接同目录 `stardew-concept.md` 的“身份、基调与世界观”“边界与约束”,以及 `stardew-architecture.md` 的“首个原型范围”“实现范围与验证”。矿井、战斗、NPC 日程、关系、钓鱼、畜牧、节日、多人和大批换装属于后续范围,本例不为它们预配首期图集。
## 视觉风格总览
视觉依据是温暖乡村、复古像素、轻度压力和可反复游玩的日常节奏,来源版本见总册。**目前没有已选定的参考图、画风卡或可验收的源素材**;以下色值和尺寸是示例策划假设,供后续视觉确认。目标运行时是新建 2D Web 原型(npm + Vite + Phaser 4.2.1)。美术源文件和导出资源尚未产出;预定资源入口为项目内 `assets/art/source/`(可编辑源文件)、`game/public/assets/art/`(PNG 和帧表 JSON)与 `game/public/assets/audio/`(音频)。运行素材由 Vite 复制到 `game/dist/assets/`,程序按构建内相对路径加载;这些是预定交付位置,不表示文件已存在。
从定调记录翻译的视觉气质:**"被四季照亮的温暖小农场"**——手绘感像素、俯视 45° 视角,春夏绿意、秋日暖橙、冬季留白,颜色随季节整体切换而不是换贴图;物件轮廓圆润、无锐利科技感。玩家一看画面就该感到:这里节奏很慢,干活是安心的。参考图位 4 张(量产流程第 3 步产出锚点图)。
## 视觉规则
## 视觉锚
- 关键词:温暖、朴素、清爽、生活感。避免血腥、霓虹、高反光写实材质、尖锐科技造型和繁密的随机像素噪点。
- 色板示例假设:草地基色 `#78A85A`、泥土 `#9D7048`、木材 `#AA724C`、纸面 `#F2E1B9`、操作提示 `#E8BE62`、不可用 `#738291`。这些是设计锚点,实际调色板及色弱可辨性须在首批视觉样张中确认;状态不能只靠颜色区分。
- 画面采用近正上方的斜俯视像素场景,地面按 16×16 世界像素网格排布。人物脚点落在格中心下沿;可遮挡的建筑/树冠在人物之上,地面和作物基座在人物之下。建筑、箱子和植物用圆润轮廓,亮面集中在左上,阴影不使用柔边渐变。
- 游戏世界用最近邻采样、整数倍缩放和像素对齐;示例假设移动端世界像素放大 3 倍、桌面端 4 倍,布局可裁剪视野但不拉伸像素。HUD 使用清晰文字与图形,不把 16px 图标放大后作为 44 CSS px 的触控热区;热区由 UI 布局提供。
- 当前范围只需晴、雨和日间至傍晚的可辨反馈。雨天在地面与图标之外加低强度冷色层和雨线;傍晚用统一环境色层。天气图示另带“晴/雨”文字,避免仅靠色调识别。季节全套换景不是首期要求。
- 关键词:温暖、手绘像素、田园、四季分明、生活感。
- 禁用关键词:阴暗压抑、血腥恐怖、高饱和霓虹、写实渲染、锐利科技风(承概念层 T3"战斗轻度"、T7"日常叙事")。
- 色板:主色 暖土绿系(草地/耕地基底)60% / 辅色 暖木棕+瓦顶红 30% / 点缀 季节信号色(春樱粉/夏浓绿/秋橙/冬蓝白)10%。昼夜·天气·季节表现:季节=色调与植被整体切换;天气=雨天全屏冷色叠加(原作 OrangeRed×0.45 实证);昼夜=时刻线性插值环境光。
- 形状语言:圆润矩形轮廓,物件以 16px 网格对齐;无 1px 高光乱线。
- 比例与轮廓:物件 16px 一档;NPC 16×32(渲染放大 4 倍);玩家可完全自定义外观。
- 光照与材质:不做真实光照——低分辨率 lightmap 乘法混合;优先级链=矿井 tint>室内 ambient>室外 outdoor(时刻插值);十种光源贴图常量够用。
- 渲染口径:纯像素、无抗锯齿、整数倍缩放(程序侧能力边界同源)。
## 类别规格
## 角色模板
下表参数均为示例假设;后续确定时应在本分册更新,不能把本段视为已经产出的资产事实。帧键按对象标识及适用的状态、方向、帧序组成;同类共性只定义一次。
- 基础规则:玩家=换装组合而非整图——19 个独立层(基础体/裤/衣/发型/饰件/配件…),每层独立图集,调色板像素 256-277 区域换色实现同图集多变色;层深=基准+层序×1e-6 保证叠加次序稳定。NPC=16×32 四方向小人+64×64 立绘(对话用)。
- 方向数:4 方向(左=右镜像:是——行走图按方向分行布局,如 64×448=4 列×14 行)。
- 动画状态:待机/走 walk=4 帧循环、每帧 200ms(帧表含毫秒级帧时长);受击/使用工具按动作逐条登记帧表。玩家帧表量大(原作 500+ 动画参数为 switch 硬编码),本项目帧表走数据表不走硬编码。
- 立绘表情:六表情索引 0-5($neutral/$happy/$sad/$unique/$love/$angry),对话文本中 `$表情` 标记驱动切换。
| 类别 | 共性规格 | 命名与交付格式 | 运行时消费 | 后续验收判据 |
|---|---|---|---|---|
| 地形图块 | 每格 16×16;地面可无透明,边缘变体不留缝;绘制时留 1px 图集挤出边防采样渗色 | `tile_{terrain}_{variant}`,PNG 图集+JSON 帧表 | 地图按 `region_id` 的格子与图层取帧;湿地块读取地块状态,不复制一张整农场图 | 每帧 16×16、图集无渗色;干湿耕地与普通土路在目标缩放下能区分 |
| 场景物 | 按占格记录脚点和遮挡高度;静态物 1 帧,交互状态单列 | `prop_{object}_{state}`,PNG 图集+JSON 帧表 | 地图对象标识决定帧;遮挡层按脚点排序,交互热点由地图数据给出 | 图像、脚点、碰撞/热点对齐;可交互物与背景有轮廓差异 |
| 玩家 | 单个 16×32 角色,不做换装层;待机每方向 1 帧、走路每方向 4 帧,工具动作是否专帧待确定 | `player_{state}_{dir}_{frame}`,PNG 图集+JSON 帧表;方向 `down/up/left/right`,右可镜像左 | 移动状态驱动待机/行走,帧表注明顺序和时长;脚点固定在帧底中心 | 四方向基准点一致,镜像后工具手势不误导;行走不跳格或抖动 |
| 作物与采集点 | 作物占 1 格,按数据侧生长状态取 16×32 透明帧;采集点包含可采和已采状态 | `{crop_id}_{stage}` / `{forage_node_id}_{state}`,PNG 图集+JSON 帧表 | 数据状态映射到帧键,成熟和可采必须有独立轮廓;状态数以数据分册最终定义为准 | 各状态有唯一帧键,无缺帧;未熟/成熟、可采/已采在移动视口能辨认 |
| 物品图标 | 16×16,透明背景,单帧;工具和产物同一盒内留 1px 内边距 | `icon_{item_id}`,PNG 图集+JSON 帧表 | 背包、商店、出售清单按 `item_id` 查图标;金额、数量由 UI 文字绘制 | 图标键与物品表逐项匹配,无空白或越界;种子、产物、工具形状可区分 |
| UI | 面板、槽位、进度条用 CSS 或九宫格按界面实现,文字走字体系统;天气图示与操作提示可为 16×16 图标 | 需要图片时用 `ui_{element}_{state}`;UI 图 PNG,文字不烘入纹理 | HUD、背包、商店、出售和日终视图读取权威状态;禁用态以图形与文字共同提示 | 数字与图标不重叠;移动端本例暂定触控热区至少 44 CSS px,桌面/移动两视口可读 |
| 音频 | BGM 暂定 OGG 循环、目标 -18 LUFS;SFX 暂定 WAV 单发,均为本例假设;时长、采样与混音参数待补齐 | `bgm_{usage}` / `sfx_{action}`,独立文件;循环点随资源给出 | 首次用户操作后启用音频;按游戏事件触发,具体绑定由技术分册补齐 | 在目标浏览器可解码,循环无接缝,事件不重复触发,反馈清楚且不盖过其他必要提示 |
## 场景模板
## 当前范围对象清单与例外
- tileset 规格:16px tile;TileSheets 级图集约 41 张+地形特征图集 38 张(作物/树);padding 1px 防渗色。
- 图层拆分:四层 Back/Buildings/Front/AlwaysFront(深度 -1/0.1/64+/-1)——地面/建筑/前景遮挡/最前;碰撞由 Buildings 层属性驱动;矿井布局池按模板拼装(原作 61 张模板,本项目首期 8~12 张)。
- 场景对象规则:多帧素材禁当静态贴图(作物生长/角色必须走帧表);单元素禁整图(区域由 tile 拼装,禁为每区域画整张立绘);地图数参照:原作 259 tmx+304 预览,本项目首期 3 区域(农场/小镇/矿井)。
清单用对象组列出有限变体,适用上面的类别规格。物品和作物标识以数据分册为准;若数据分册尚未给完整首期清单,下列命名只作示例,**不能据此宣称原型素材范围已全量对账**。
## UI 视觉
| 对象或明确对象组 | 类别 | 标识/数据绑定 | 状态与变体 | 规格例外或无图像资产的处理 | 消费位置 |
承 UI 系统文档界面清单(HUD/背包/商店/对话/日终结算五界面)。视觉语言:木质面板底+纸张质感对话框;信息分层——价格信息永远暖金、锁定/禁用永远灰蓝、日终收入单列。字体用位图字体(原作 5 fnt 位图字体实证)。触控版式热区 ≥44px 与程序侧输入表同源。特效走程序动画(按帧表播图集区域)+粒子,不逐特效画整图(原作 LooseSprites 156 张 UI/杂项图集规模参照;最大图集实测 1920×1376)。
## 素材规格契约
| 素材 | 规格(尺寸/帧数/方向数) | 命名规则 | atlas 格式 | 验收 | 绑定 |
|---|---|---|---|---|---|
| 农场、小镇、基础采集区域 | 地形图块/地图 | `region_id`:`farm`、`town`、`forage`(示例假设) | 草地、土路、干耕地、湿耕地、边界与出入口;必要的相邻边缘变体 | 每区由 tile 与对象图层拼装;地图格、出口和碰撞数据需随地图一同交付,不能以整图代替 | S04 场景加载、S03 地块展示 |
| 农舍外观、出货箱、小镇种子商店门牌 | 场景物 | 地图对象 `farmhouse`、`shipping_bin`、`seed_shop` | 默认;出货箱可交互、商店开/关由 UI 文本或标记提示 | 农舍可跨多格,需给实际占格与脚点;不为商店首期制作有日程的店员 | S04 地图与 S09 商店/出售入口 |
| 野外采集点 | 作物与采集点 | `forage_node_id` 对应地图资源点 | 可采、已采;刷新后回可采,触发时机待 S04/S05 定义 | 采集物外观与其背包图标可以不同 | S04 资源点、S05 采集反馈 |
| 防风草作物 | 作物与采集点 | `crop_id=crop_parsnip`(数据分册局部示例配置) | 播种后各生长阶段、成熟;浇水通过地块湿态呈现 | 数据样例仅给 `growth_days=4`,四次满足条件的跨日不等于四个视觉阶段;阶段数和映射待定 | S03 地块投影 |
| 玩家 | 玩家 | `player` | 四方向待机、行走;工具动作待确定 | 不做 19 层换装、立绘或 NPC 表情 | S04 移动、S03 农务、S05 采集 |
| 防风草种子、防风草 | 物品图标 | `item_id=parsnip_seed`、`parsnip`(数据分册局部示例配置) | 每物品 1 图;数量与价格均由文字显示 | 只覆盖局部示例配置,不代表首期全量物品 | 背包、商店、出售清单 |
| 采集物、锄头、水壶 | 物品图标 | `wild_berry`、`hoe`、`watering_can` 是待数据确认的示意标识 | 每物品 1 图;数量与价格均由文字显示 | 数据规则与数值未定,不能据此进入全量生产;金币无需物品图标 | 背包、商店、出售清单 |
| 时间/天气/体力/金钱、背包、商店、出售、日终与存读档 | UI | S01/S02/S07/S09 状态与界面标识 | 晴/雨图示,体力进度与低体力提示,可买/不可买、可卖/不可卖、结算前后 | 数值、名称、日期、价格和说明由 UI 文本绘制;进度条和槽位可程序绘制,按界面无需逐状态出图 | HUD 与各界面 |
| 日常环境音乐与行动反馈 | 音频 | 暂定 `bgm_daily`,以及耕地、播种、浇水、收获、采集、购买、出售、日终的 `sfx_{action}` | 单一日常循环与各成功事件单发;失败提示是否需要独立音效待定 | 不预填四季或矿井音乐;精确事件、文件名与音量映射待补齐 | 场景音频、S03/S05/S09 与日终反馈 |
| 物品图标 | 16×16,1 帧 | `icon_{item_id}` | JSON atlas | 技术+视觉 | `item_*` 全量(参照原作 807;本项目首期 ~120 行) |
| 作物 | 16×32×相位帧(4~5 相位,每相位 1~2 帧) | `crop_{crop_id}` | JSON atlas | 技术+视觉 | `crop_*`(参照原作 50) |
| 玩家换装层 | 每层独立图集,walk 4 帧×4 方向 | `farmer_{layer}_{state}_{dir}` | JSON atlas | 技术+视觉 | 豁免(角色非物品,登记于本表) |
| NPC 行走+立绘 | 行走 16×32 四方向行布局;立绘 64×64×6 表情 | `npc_{id}_walk` / `npc_{id}_portrait_{expr}` | JSON atlas | 技术+视觉 | `npc_*`(参照原作 34 社交 NPC/101 立绘;本项目首期 8 位) |
| tileset | 16px,边缘连接变体 | `tile_{theme}_{variant}` | JSON atlas | 技术+视觉 | 豁免(场景组件) |
| UI 面板 | 9 宫格切片,3 态 | `ui_{element}_{state}` | JSON atlas | 技术+视觉 | 豁免(UI) |
| BGM | ogg,-18LUFS,循环点标记 | `bgm_{season}` 4 首+矿井 1 首 | — | 响度+循环 | 豁免(音频契约) |
| SFX | wav 单发 | `sfx_{event}`(事件↔音效映射表登记) | — | 同帧触发 | 豁免(音频契约) |
## 后续生产与接入验收
- 绘制工艺:按项目实际制作路径逐类记录参数与封装流程;施工环境无产出通道时规格先行锁定、状态如实登记"缺失"。
- 音频契约说明:原作 XACT cue 名 435 候选/代码引用 230 个——本项目首期 SFX 事件 20 只起步,按事件总线 `sfx_event` 映射表登记,不逐 cue 复刻。
- 豁免类型仅限:程序化生成(矿井布局由表驱动拼装)/ UI 文本 / 本期不需要——每项豁免在契约行写明。
- 交付时保留可编辑源文件,并按类别导出 PNG 与帧表 JSON。帧表至少给帧键、矩形、脚点、状态、方向、帧时长;地图另给格子、图层、对象脚点、出口和碰撞数据。生产前先用少量地形、角色、作物、图标和 UI 样张核对色板与比例,再按已定规格扩充;样张数量由实际疑点决定。
- 技术验收逐项对照**最终数据清单**核对对象键:图集和帧表能解析;帧矩形不越界;16×16 图标/地形与 16×32 玩家符合约定;透明通道、边缘和脚点正确;作物与采集状态都有帧。接入场景后移动、播种、浇水、跨日成长、采集、买卖和日终均能取到正确帧或程序绘制状态,缺帧或错误状态即不通过。
- 视觉验收在桌面与移动视口截取农场、小镇、采集、背包、商店、出售和跨日后的画面,对照本分册检查乡村像素风、角色脚点、干湿地块、作物未熟/成熟、可采/已采、天气与禁用态。请观察者不看说明指出可操作对象与关键状态;若只能靠颜色或反复试错识别,就需调整形状/文字提示后复验。
- 这套检查是**后续生产和接入的判据**,不表示已有素材通过。新增物品、区域或状态时,先更新数据/系统清单,再更新本页对象、帧键和消费映射。
## 资产状态表(asset manifest)
## 当前未决问题
| asset_id | 规格 | 绑定 | 状态 | 验收记录 | contract_version |
|---|---|---|---|---|---|
| icon_item_*(首期 ~120 行,逐 item_id 一行) | 16×16 | `item_*` | 缺失 | — | 1 |
| crop_*(50 行) | 16×32 相位帧 | `crop_*` | 缺失 | — | 1 |
| farmer_*(19 层图集) | 4 帧×4 方向 | 豁免 | 缺失 | — | 1 |
| npc_*_walk / _portrait(8 位×7 件) | 16×32 / 64×64×6 | `npc_*` | 缺失 | — | 1 |
| tile_*(3 主题变体组) | 16px 变体 | 豁免 | 缺失 | — | 1 |
| ui_*(5 界面套件) | 9 宫格 3 态 | 豁免 | 缺失 | — | 1 |
| bgm_*(5 首) | ogg -18LUFS | 豁免 | 缺失 | — | 1 |
| sfx_*(20 只) | wav | 豁免 | 缺失 | — | 1 |
| 问题 | 对当前施工的影响 | 下一步与需更新的位置 |
- 状态单向流转:缺失 → 草稿 → 已交付 → 已验收 → 已接入;驳回退回草稿并记原因。
- 验收两维:技术(尺寸/透明/帧数/命名)+ 视觉(对照视觉锚);两维都过才进"已验收"。
- **每个 gameplay 可见对象必有一行或显式豁免——没有第三种状态**:物品图标逐 item_id 与数据侧物品表逐行对账(参照规模:原作 Characters 215 png/Portraits 101/TileSheets 41/TerrainFeatures 38/LooseSprites 156)。
- 程序接入后填消费点(哪个模块加载、事件映射),`contract_version` 变更须重验收。
## 量产流程与验证
1. 概念候选 4 张(农场一角/角色/物品图标/UI 面板各 1 方向稿)→ 2. 人选方向(用户确认)→ 3. 锚点图 4 张 → 4. 锁圣经 → 5. 写契约(本文件已锁)→ 6. 小批 8 张(icon_item 子集:防风草种子/防风草/木材/石头/铜矿/锄头/水壶/出货箱)→ 7. 技术检查(尺寸/透明/命名/atlas 解析)→ 8. 接入程序(v0.1 里程碑)→ 9. 运行时截图验收(桌面/移动双视口下 16×16 图标与作物相位可辨、四季色调正确)→ 10. 扩产(8→120→全量)。
## 开放问题回执
| # | 问题 | 去向 |
|---|---|---|
| 数据分册目前只有 `parsnip_seed`、`parsnip` 与 `crop_parsnip` 的局部示例配置;完整物品/采集点 ID 与作物视觉阶段未定 | 无法最终对账图标和作物帧键,也不能给出全量资产数;`growth_days=4` 不能代替阶段映射 | 数据分册定稿后填入对象清单及物品、作物、采集点帧键映射 |
| 技术分册暂定农场 80×65 格、小镇 50×40 格;采集区域尺寸、各区域出口、遮挡物占格与碰撞仍不完整 | 地形和场景物的实例数量、脚点与地图数据无法施工 | 地图规格确定后补地图对象表和场景物例外,并同步 S04 |
| 视觉锚图、实际调色板与字体尚未选定 | 可按文字规则做方向稿,但最终视觉一致性与 UI 字符可读性仍需评审 | 选择可访问的锚图与字体资源后更新“范围与设计依据”“视觉规则”“类别规格” |
| 工具动作帧和具体 UI 布局尚未确定 | 农务动作与移动端操作反馈无法完成逐状态切图 | 交互规格确定后补玩家动作帧和 UI 状态映射 |
| 图集 JSON 格式、帧时长与音频参数/事件映射未全定 | 程序无法直接加载所有动画或绑定声音 | 明确与 Phaser 加载方式一致的格式和映射,同步技术分册 |
本例展示如何写出当前范围的规格与后续验收方法;以上缺口仍影响实际施工,因此不宣称首个原型的美术策划案已经完备。
| 1 | 换装系统首期是否做全 19 层(或缩到 5 层) | → 台账代决(建议首期 5 层:基础体/裤/衣/发型/饰件;台账 D-17) |
| 2 | 锚点图方向需用户确认 | → 施工期提案卡 |
| 3 | 位图字体 vs 矢量像素风字体 | → 小批阶段随 UI 套件定 |
@@ -1,75 +1,98 @@
# 数据与配表:《星露谷物语》题材写法示例
# 数据与配表:《星露谷物语》(TDD 金样 · 数据与配表)
> 本例只演示首个日常原型的数据侧写法:农场与小镇、基础采集、耕种、商店购买、出售、跨日成长。下列数值是用于演示计算的**项目假设**,不是原作实证或解包数据。本例尚未填满当前范围,未通过策划文档验收,更不代表游戏成品验收。
> 状态:accepted(结构定稿+首期全量填充验算通过) | 基于:各系统文档交接节汇总 + 归 TDD 素材两份提取件(S06 数值结构/架构字段字典) | 验收:check@C-2026-09-11-v1 结论 无 blocker
> 实证计数来源:星露谷 1.6.15 解包知识库 v3(13 张数据表,提取脚本断言通过;快照 stardew-1.6.15-7f1e5b8e)。写新项目时按本项目系统交接节重建,计数仅作规模参照。
## 数据范围与归属
## 数据表总清单
| 数据或配置 | 维护系统 | 原型用途与消费方式 |
|---|---|---|
| 日期、天气、跨日触发 | S01 时间 | S03 读取日期和天气决定成长;S09 接收日终结算时点 |
| 行动体力成本与恢复 | S02 体力 | 农务和采集动作提交成本;数值尚未确定 |
| 地块与作物 | S03 农场 | 引用 S07 的种子与产出物品 ID;播种、浇水、跨日成长和收获由 S03 判定 |
| 农场、小镇、资源点位置及可用状态 | S04 地图 | S05 读取可采集资源点并在成功后请求更新;点位和刷新尚未确定 |
| 采集获得物与经验规则 | S05 采集 | 成功时向 S07 请求物品入账、向 S08 报告经验;产物与判定尚未确定 |
| 种子、作物产物、采集物的身份与持有 | S07 物品 | 由 S03/S05 产出、S09 买卖;背包容量尚未确定 |
| 农务与采集经验、等级 | S08 成长 | 接收活动结果;本例只给出首级阈值的演示值 |
| 起始货币、商品价格、库存、出售与出货 | S09 经济 | 商店和出货箱使用同一价格定义;营业、库存和结算规则尚未确定 |
表或文件的拆分由实现方式决定,上述数据归属不随存储方式改变。当前只需要稳定引用:`parsnip_seed` 是种子物品,`crop_parsnip` 引用该种子与 `parsnip` 产出物品。S09 维护其买价和卖价,不在 S03/S07 复制价格。
## 已知字段契约与示例配置
下表只覆盖已出现的字段。ID 是不随显示名称变化的字符串;引用不存在时不能把动作算作成功。数值单位写在字段定义中,不能把游戏日、体力、金钱和经验混用。无默认值的字段必须显式给值;本例没有授权用 `0`、空值或估值替代缺失配置。
| 字段及维护者 | 类型与单位 | 本例约束/默认值 | 消费方式 |
| 表格组 | 建议表名 | 主要维护系统 | 实证规模(原作 1.6.15) |
|---|---|---|---|
| S07 `item_id` | 非空字符串 | 必填、唯一;无默认值 | S03、S05、S09 以 ID 引用物品 |
| S03 `crop_id`、`seed_item_id`、`harvest_item_id` | 非空字符串 | 必填、唯一作物 ID;两个物品引用无默认值 | 播种消费种子;收获请求产出物品入账 |
| S03 `growth_days` | 非负整数,游戏日 | 必填;本例 4;无默认值 | 每次满足成长条件的跨日推进一次 |
| S09 `buy_price`、`sell_price`、`starting_currency` | 非负整数,金 | 必填;无默认值 | 买入扣款、出售入账、开局钱包 |
| S08 `farming_xp_per_harvest`、`farming_level_1_xp` | 非负整数,经验 | 必填;无默认值 | 成功收获入账并比较等级阈值 |
| 验算 `seed_count` | 非负整数,包 | 仅场景输入,本例 15;不是商店库存默认值 | 验算一次购买和播种的总量 |
| 物品与经济 | 物品表、品质表、商店表、商店库存表、价格表 | 物品与制作、经济与商店 | 物品 807×29 类;商店 77 店 897 条库存(含店级 PriceModifiers) |
| 农场内容 | 作物表、动物表、设施表、加工配方表 | 农场经营 | 作物 50 全字段;机器 39 台全 OutputRules |
| 活动内容 | 采集点表、钓鱼点表、鱼类表、敌人表、敌人行为表、遭遇表、战利品表 | 采集/钓鱼/战斗 | 怪物 51 条配置;怪物 AI 矩阵 30 类移动原型 |
| 物品制作 | 通用配方表、配方解锁表 | 物品与制作 | 配方 231(烹饪 81+工艺 150,全原料/产出/解锁) |
| 玩家成长 | 技能表、等级经验表、能力节点表、工具升级表、效果表 | 成长与技能 | 职业 30 全效果钩子(51 钩子+6 数据驱动);附魔 34 逐项数值;经验曲线代码常量 |
| NPC 与任务 | NPC 表、关系等级表、礼物偏好表、任务表、奖励表、事件条件表 | NPC/任务/事件 | NPC 送礼 34NPC×4 档+全局 5 档;事件 258/条件码 39 |
| 时间与世界 | 日期季节表、天气表、节日表、营业时段表 | 时间与日程、事件与节日 | —(代码常量+日程数据驱动) |
| 文本与展示 | 文本表、UI 提示表 | UI 与文本呈现及各内容系统 | 11 语言按后缀拆分(含 zh-CN) |
| 维护系统 | 示例记录或参数 | 已知值与引用 | 仍缺的当前范围配置 |
|---|---|---|---|
| S07 | `parsnip_seed`、`parsnip` | 分别是防风草种子和产物的示例物品 ID | 完整物品字段、背包容量、堆叠和展示文案 |
| S03 | `crop_parsnip` | `seed_item_id=parsnip_seed`;`harvest_item_id=parsnip`;`growth_days=4 游戏日` | 地块初态、种植季节、浇水/天气成长细则、阶段视觉映射、品质与收获数量规则 |
| S09 | 防风草种子买价、产物卖价 | 种子 `20 金/包`;普通品质产物 `35 金/个`;开局 `500 金` | 商店 ID、营业时段、库存及补货、售价适用条件、出货箱结算细则 |
| S08 | 农务收获经验与首级阈值 | 成功收获 `crop_parsnip` 获 `8 经验/株`;累计 `100 经验` 达 1 级,均为示例假设 | 采集经验与其他当前可达等级、升级反馈 |
| S04 | 农场、小镇地图尺寸 | 相邻技术样例使用 `16px` 网格、农场 `80×65` 格、小镇 `50×40` 格,均仅作本例地图规模假设 | 地图层数据、连接点、可采集点位、可用状态与刷新配置 |
| S01 | 日期与成长 | 一次满足成长条件的跨日记为 `1 游戏日`;S03 负责累计 | 游戏日长度、天气概率、跨日通知与结算输入 |
(表格拆分是生产组织方式,不改变主数据归属。原作同套模型同时服务本体与模组生态——静态表为结构化 JSON-in-XNB,由 DataLoader 按需缓存。)
以上是**局部示例配置**,不是可加载的完整数据集。尤其不能凭两个物品 ID、一株作物和地图尺寸推断物品、地块、地图、商店或采集已配齐。所有可见名称、交互提示、商店文案、收获及结算文案也需在本套 TDD 中逐条确定;本例尚未提供这些正式文案。
## 字段字典与 ID 命名规范
## 用已知数值做局部验算
- ID 命名:小写 snake_case,`对象类型_名称_必要时加阶段`(如 `item_turnip`);全局唯一、废弃不复用。(原作实证:1.6 起用限定 ID 如 `(O)123` 统一引用 807 物品——原理同源:ID 不含人话、不随语言变。)
- 通用字段:`*_id` / `display_name_text_id` / `description_text_id` / `condition_id` / `enabled_state`(active·draft·disabled·deprecated)/ `sort_order` / `designer_note` / `unit`(数值字段必填:time_slice·game_day·currency·stamina·exp)。
- 常用后缀:`_amount`(配单位)/ `_cost` / `_rule_id` / `_condition` / `_time` / `_duration` / `_state` / `_text_id`。
- 类型与空值:数值栏禁"约/无/待定";空值=不适用≠0≠无限(无限制库存用 `stock_type=unlimited`,不用 999999);布尔 true/false;多值一律关系子表(多材料配方禁拼一格)。
- 引用完整性:`item_id`→物品表;`location_id`→区域表;`npc_id`→NPC表;`quest_id`→任务表;`recipe_id`→配方表;`condition_id`→条件表;`text_id`→文本表。删除先置 `deprecated` 并查引用。
- 枚举实证注意:品质枚举值为 0/1/2/4(银=1、金=2、铱=4)——所有 `(1+0.25×quality)` 型公式乘数因此是 1.25/1.5/2.0;枚举值是语义约定,禁止想当然重排。
场景假设:开局持有 `500 金`,商店可一次卖出 `15 包`示例种子,玩家有 `15 块`可用地且逐块播种;其后每块都满足四次跨日成长条件,均产出一个普通品质防风草,全部成功入账并按示例价格出售。这些条件是验算输入,不是已经确定的系统配置。
## 公共条件表
| 行动与状态 | 计算 | 可确认的结果 |
|---|---|---|
| 买 15 包种子 | `15 × 20 = 300 金`;`500 − 300 = 200 金` | 购种后余 `200 金`,前提是库存、营业与背包允许交易 |
| 播种并成长 | 消费 `15 包`;每株满足 `4` 次跨日成长 | 可推得最早在满足第四次成长条件后收获;浇水、天气和日终精确规则仍未配置 |
| 收获 15 株 | `15 × 1 = 15 个`;`15 × 8 = 120 经验` | 假设均为普通品质、每株一产物且物品入账成功,农务经验达到示例首级阈值 `100` |
| 全部出售 | `15 × 35 = 525 金`;`200 + 525 = 725 金` | 假设交易或日终出货成功,最终金钱 `725`;相对购种投入毛利 `525 − 300 = 225 金` |
| condition_id | condition_type | target_id | operator | required_value | enabled_state | 备注 |
|---|---|---|---|---|---|---|
| `condition_day_2` | `date_day` | `season_spring` | `>=` | 2 | `active` | 春季第 2 日后可触发 |
| `condition_shop_unlocked` | `progress_flag` | `flag_general_store_open` | `==` | 1 | `active` | 杂货店已开放 |
| `condition_skill_farming_1` | `skill_level` | `skill_farming` | `>=` | 1 | `active` | 农务技能达到 1 级 |
| `condition_blacksmith_open` | `schedule_open` | `schedule_blacksmith_default` | `==` | 1 | `active` | 铁匠铺当前处于营业时段 |
| `condition_recipe_repair_path` | `quest_completed` | `quest_repair_path` | `==` | 1 | `active` | 修路任务完成后解锁基础洒水器配方 |
这只验证了给定假设下的数量和金钱/经验算术。没有行动体力、实际耗时、采集产出与成本、商店库存、背包容量、天气概率及跨日结算顺序,无法证明玩家能走完整个流程,也无法判断收益、节奏和平衡。补齐这些数据后,需以真实配置重算农务与采集的同日取舍、跨日成长和出售投资闭环。
(复杂条件拆条件组+条件行;全项目只此一个条件入口,程序实现一次 `check(condition_id)`。实证参照:原作 258 事件共用 39 个条件码——条件收敛是可达到的规模。)
## 数据检查与结论
## 工作簿组织与建表顺序
| 检查对象 | 已做的文档检查 | 结论与缺口 |
|---|---|---|
| 已列示例 ID | `crop_parsnip` 的两个物品引用均出现在本例中;价格只在 S09 定义 | 局部引用及归属一致;商店、地图、采集点等真实引用尚未定义 |
| 数值与单位 | `15×20=300`、`500−300=200`、`15×35=525`、`200+525=725`、`15×8=120`,单位对应金/经验 | 上述假设下算术成立;行动、产量、品质、库存等约束未验 |
| 当前范围完整性 | 对照 S01/S02/S03/S04/S05/S07/S08/S09 的当前原型职责 | 采集配置、地图点位、行动成本、容量、商店与全部可见文案缺失 |
| 关键循环 | 已计算买种到卖出的局部链条 | 农务与采集并行选择、跨日结算及存读档后的结果未能验算 |
| 工作簿 | 工作表 |
|---|---|
| `世界与地图.xlsx` | 日期季节、天气、日程、区域、区域连接、活动入口 |
| `农场与制作.xlsx` | 地块、作物、动物、设施、加工配方、通用配方 |
| `物品与经济.xlsx` | 物品、品质、装备、价格、商店、商店库存、货币 |
| `活动与战斗.xlsx` | 采集点、掉落、钓鱼点、鱼类、敌人、行为、遭遇 |
| `成长与任务.xlsx` | 技能、等级经验、能力节点、工具升级、NPC、关系、任务、目标、奖励 |
| `事件与文本.xlsx` | 节日事件、事件阶段、事件条件、文本、UI 提示、教程 |
本册**未完成**,不构成策划文档验收通过的记录。没有运行游戏、构建或试玩;表中结果仅是可复核的局部文档检查。
建表顺序:①物品表(公共 item_id)→ ②作物表 → ③区域与连接表 → ④NPC 表 → ⑤配方表 → ⑥价格与商店库存表 → ⑦任务/目标/奖励表 → ⑧敌人/掉落/技能/事件表。
每完成一组查三件事:引用 ID 存在 / 条件有负责系统 / 同一数值只有一个系统维护。
## 待解决问题
## 表格-程序契约
| 问题 | 对当前施工或验算的影响 | 下一步 |
|---|---|---|
| 基础采集与地图点位 | 无法实现资源点发现、判定、刷新和产物入账 | 补 S04 点位/状态及 S05 获得物、品质、经验规则,连同物品引用验算 |
| 行动成本与日期天气 | 无法验证农务和采集能否在同一天完成,也不能确定四次跨日的实际路径 | 补 S01/S02/S03 的时间、体力、浇水和跨日数据后重算 |
| 背包、商店与出货 | 数量和金额虽可计算,仍无法验证交易与结算是否可执行 | 补 S07 容量及 S09 营业、库存、售价、结算配置和失败处理 |
| 当前范围其余数据与文案 | 几条示例记录不足以施工,玩家反馈也无权威文本 | 按确定的内容范围填满物品、作物、地图、采集、商店、成长及文案,再检查完整性 |
1. 加载顺序按引用拓扑:主数据 → 关系 → 条件 → 文本(最后)。
2. 启动期全量校验(外键/枚举/单位);运行期全部 id→对象字典 O(1) 查找。(实证参照:原作按需缓存加载+`ContentHashes.json` 逐文件 MD5 校验拒损坏。)
3. 条件求值统一 `check(condition_id)`,全部系统复用。
4. enabled_state 生命周期:active 加载;draft 调试可见;disabled 不加载;deprecated 不加载但留 ID 占位。
5. 单位类型化(time_slice/game_day/currency/stamina/exp 进类型系统,同列禁混单位)。实证锚点:`700ms=10 游戏分钟`为运行时常量,配表侧时间单位统一 time_slice,禁现实秒混入。
6. 多值一律关系子表;运行期无"解析逗号拼接"代码路径。
7. 改表 → 验收过检(blocker=CI 红灯)→ 进包;`data_version` 为迁移依据(实证参照:原作存档迁移器按版本处理旧字段)。
8. 随机契约:影响掉落/品质的 roll 绑定「世界日+存档 ID+位置/主体」种子(防读档刷结果;原作行为级种子实证:收获 `CreateRandom(x×7, y×11, DaysPlayed, uniqueID)`)。
## 数值填充与验算
- 填充代决台账:
| 表 | 字段 | 默认值 | 依据 | 推翻条件 |
|---|---|---|---|---|
| 等级经验表 | skill_cumulative_xp | 100/380/770/1300/2150/3300/4800/6900/10000/15000 | 代码常量(Farmer.cs 实证) | 原型期曲线过陡/过缓 |
| 作物表 | 防风草 price/days/xp | 35 金/4 日/8 xp | 原作作物表实证(crop 472:phases 1-1-1-1,xp_per_harvest 8) | 前 5 日验算不闭合 |
| 经济表 | 买卖价差 | 商店价=2×基价×品质系数;出售所得=其半 | 原作一对出售方法实证 | 新手期现金流断裂 |
| 战斗表 | 受击无敌帧 | 450ms(按武器类型 2/3 除) | 原作 takeDamage 实证 | 手感测试受击连按 |
- 前五日闭环验算(防风草路线,起始 500 金实证口径):
| 日期 | 主目标 | 关键行动 | 主要成本 | 主要获得 | 结果 |
|---|---|---|---|---|---|
| 第 1 日 | 建立基础生产 | 购防风草种子×15(20 金/包)、开垦播种浇灌、采集少量木材 | 300 金;约 30 体力;约 8 时间片 | 15 块已播种地;少量木材;农务经验 | 进入等待成长阶段 |
| 第 2 日 | 接社区引导 | 浇灌、采集木材、与工匠对话推进修路任务 | 约 25 体力;约 8 时间片 | 任务材料进度;少量经验 | 任务明确指向自然区域 |
| 第 3 日 | 补足任务材料 | 浇灌、采集木材与铜矿、返回小镇 | 约 35 体力;约 12 时间片 | 木材 20、铜矿 5(或进度);采集/战斗经验 | 可提交修路任务 |
| 第 4 日 | 收获+解锁 | 收 15 防风草(35 金×15=525 金、8 xp×15=120 xp→农务 1 级)、提交任务领奖 | 任务材料;约 10 时间片 | 525 金;基础洒水器配方;林间区域开放 | 现金流回正+新活动选择 |
| 第 5 日 | 验证扩展循环 | 浇灌、赴林间采集或钓鱼、出售部分产物 | 约 30~45 体力;约 14 时间片 | 新资源、活动经验、可售物品 | 循环从单一农务扩展为农场+探索 |
- 收益链校验:`item_seed_parsnip(20金) → crop_parsnip(4 日) → item_parsnip(35 金) → 出货箱日终结算 → 种子复购(单包毛利 15 金)`(逐环引 ID,全链存在)。
- 验算结论:第 1 日不要求做完,播种即进展;第 4 日奖励同时给资金/配方/区域三样;第 5 日出现农场与探索取舍但两条路线都可行。
## 验收
- 验收记录:check_id / workbook / sheet / data_version / check_type(primary_key·reference·enum·unit·range·business_rule·duplicate_ownership)/ severity(blocker·warning·note)/ result / issue / owner / resolution。
- 五查必过:主键唯一不空;外键存在且目标非弃用;枚举有清单(品质枚举 0/1/2/4 单独登记);单位可判且同列不混;无违规负数、`duration=0` 仅即时。
- 两查复核:业务规则(季节窗口相容、目标有验证系统、奖励一次、配方输入可达——防风草种子→收获→出售链全通);重复归属(价格只由经济表维护、品质只由收获规则维护)。
- 三级处置:blocker 禁止扩内容;warning 记负责人与计划;note 不阻断。
- 工具化实证口径(参照知识库做法):提取脚本逐表断言(行数/字段/枚举);对账器做表间交叉对账(代表资产级 50 键全对账);反例套件 5/5 拒绝。
- 最近验收结论:check@C-2026-09-11-v1——五查全过、两查复核通过、blocker 清零(结构、规则或字段语义一变,受影响链路全部重验)。
@@ -1,48 +1,59 @@
# TDD 总册:《星露谷物语》日常原型示例
# TDD 总册:《星露谷物语》
## 当前范围
> 状态:active(v0.1 里程碑期) | 基于 GDD:架构层@v3 + 各系统交接节
首个日常原型包括农场、小镇与基础采集区域,覆盖 S01 时间、S02 体力、S03 耕种、S04 地图、S05 基础采集、S07 物品、S08 基础成长和 S09 商店,以及 UI 和存读档。单日观察计划与取舍,多日覆盖作物成长、出售和再投资。
## 自足性检查(2026-09-06 生产态复评)
矿井战斗、钓鱼、畜牧、制作、NPC 关系与日程、社区目标和节日留待后续,不以完整版本的内容量作为本次施工范围。
| # | 施工方的问题 | 答案在哪 | 状态 |
|---|---|---|---|
| 1 | 七个 P0 系统怎么行为? | 01 收编章(P0 七系统规则全文已收编@v1;S06 P1 要点已收) | **过** |
| 2 | 表里有多少行内容、文本全填了吗? | 03 全量填充(作物8/敌人3/NPC12/文本40/物品46/配方14 全填,第八查全绿) | **过** |
| 3 | 每个界面长什么样、怎么走? | 01 UI 交互规格(HUD/背包/商店/对话/结算五界面全) | **过** |
| 4 | 每份素材什么规格、谁验收过? | 02 资产状态表 42 行全登记(完成度 12/42,缺口=量产排期非规格缺口) | **过(规格)**/量产进行中 |
| 5 | 代码怎么组织、跑在哪? | 01 代码组织+能力边界(三态全落位) | **过** |
| 6 | 怎么算做完? | 01 里程碑三判据+三件验收 | **过** |
**本套是未完备的写法示例,尚不能仅凭 TDD 实现整个原型。** 玩法数值与素材规格为示例假设;本例选用新二维 Web,npm + Vite + Phaser 4.2.1 则按总纲约束执行。没有可核验的构建、试玩或资产验收证据。
**结论:六问全过——TDD 规格已自足,施工方 可只凭本 TDD 开工。**
剩余非规格缺口(不阻塞开工,按里程碑推进):①P1 四系统(S05/S10/S11/S12)施工前补文档并收编;②资产表 30 行量产(按十步流程排期);③B 级两项(背包容量、生命体力共享)在 v0.1 存档实现前收口。
## 分册索引
## 三件状态
| 项目产物 | 包内样例 | 内容 |
| 件 | 状态 | 版本 | 读者 | 一句话结论 |
|---|---|---|---|---|
| 01 技术实现 | reviewed | v0.2 | 程序 | P0 铁底七件全部落位(native 4/emulated 3),无 gated;v0.1 判据=一个游戏日全流程 |
| 02 美术圣经 | locked(锚点已锁) | v1 | 美术 | 视觉锚七件套从 T1~T7 翻译完毕;资产表 ~40 行全登记,农夫已接入、芜菁已验收 |
| 03 数据与配表 | accepted | ck-001 | 数值+程序 | 七查过、无 blocker、2 warning(公共索引表未建、背包容量未定案);前五日验算通过 |
## 跨件契约速查
| 缝 | 契约 | 权威在 |
|---|---|---|
| `01_技术实现.md` | `exemplars/stardew-tdd-tech.md` | 行为与协作、Phaser 工程、UI、构建与验证计划 |
| `02_美术圣经.md` | `exemplars/stardew-tdd-art-bible.md` | 首期视觉依据、类别规格、素材清单与接入标准 |
| `03_数据与配表.md` | `exemplars/stardew-tdd-data.md` | 数据定义、示例配置、局部计算与待补验算 |
| 素材绑定 | 作物绑 `crop_{id}`、工具绑 `item_`、敌人绑 `enemy_{id}`、NPC 绑 `npc_{id}`(ID 全部查 03 字段字典指向的表) | 03 字段字典 |
| 视觉翻译链 | `cozy-pixel-countryside` 溯源概念层 T1/T4/T7;四季色板=日单位与季节推动的视觉形态 | 概念层@v3 第 2 节 |
| 加载顺序 | 主数据(物品/敌人)→ 关系(掉落/配方)→ 条件(condition 表)→ 文本(text 表最后) | 03 契约七条① |
| 帧表格式 | `farmer_{anim}_{dir}_{frame}` JSON 帧表:圣经契约列的格式=程序侧帧动画节直接解析的格式 | 01 §能力边界 |
| 交互热区 | 触控热区 ≥44px;圣经 UI 节与 01 输入表同源(热区按钮规格一字不差) | 01 输入表 |
| 音频规格 | BGM ogg 循环+循环点标记 -18LUFS、SFX wav 单发——圣经契约与 01 音频表触发实现一致 | 02 音频契约 |
| 昼夜色调 | `tint_{phase}` 四档程序色值表,豁免绑定、拥有者=美术圣经资产表 | 02 资产状态表 |
| 拥有者总则 | 数值事实归 03(价格只在经济表);生产状态归 02(素材验收记录);技术事实归 01(缩放档位) | 架构层@v3 |
## 来源与版本
## 开放问题回执汇总
采用同包内 `stardew-concept.md`、`stardew-top-design.md`、`stardew-architecture.md` 的 2026-09-27 修订内容,以其“首个日常原型”范围为本例设计基线。技术、数据、美术三分册按这一范围共同维护,具体示例参数由对应分册明确,不把原作解包快照或未附带的外部资料当作施工依据。
| # | 来源件 | 问题 | 去向 | 状态 |
|---|---|---|---|---|
| 1 | **01** | 背包格子还是重量容量(阻断:影响存档与 UI) | 概念层决策卡 | **待用户(B 级置顶)** |
| 2 | 02 | NPC 对话立绘 +12 张(影响 UI 结构与工时) | 决策卡 | 待用户(B 级) |
| 3 | 01 | 矿井逐层生成是否本期 | 台账代决(建议 P2) | 待登记 |
| 4 | 02 | 节日专属装饰 P1/P2 | 台账代决(建议 P2) | 待登记 |
| 5 | 02 | 矿井色板 1 套 vs 3 套 | 台账代决(建议 1 套+亮度递减) | 待登记 |
| 6 | 03 | condition/text/station/behavior 公共索引表 | 03 warning(记负责人) | 进行中 |
系统文档编号沿用架构。当前未随包提供全部系统的完整正文,也未形成可施工快照;补齐时记录实际采用的来源及版本,同步受影响分册,不能将旧的通用版本占位当作已完成收编。
## 验收总状态
## 跨分册约定
| 件 | 最近验收 | blocker | 结论 |
|---|---|---|---|
| 01 | 构建通过+静态检查全绿;双视口验证待 v0.1 联调 | 0 | 结构合格 |
| 02 | ck-a01~a03:农夫接入✓、芜菁两维过(1 warning)、春瓦技术过视觉待锚点 | 0 | 小批已过闸,允许扩产 |
| 03 | ck-001 七查全跑 | 0(2 warning) | 允许内容扩充 |
| 约定 | 当前结论 | 维护位置 |
|---|---|---|
| 工程与产物 | 新二维 Web 使用 npm + Vite + Phaser 4.2.1;`game/dist/index.html` 为预览与导出入口 | 01 当前范围与工程约束 |
| 状态与数据 | 各系统维护所拥有的状态;UI 展示,存档保存和恢复;配置标识与引用定义集中维护 | 01 行为与接口、03 数据定义 |
| 视觉与绑定 | 暂定 16px 网格、16×32 角色、16×16 物品图标;素材按其消费对象绑定,不全部强绑 item_id | 02 类别规格与素材清单 |
| 配置与资源加载 | 数据与素材随构建进入 dist,具体路径与消费接口需共同补齐 | 01 代码、接口与数据;02、03 对应定义 |
| 输入与 UI | 桌面键鼠、移动触控;本例按钮热区暂定至少 44 CSS px,容量未定前不能宣称背包布局完整 | 01 界面与操作、02 UI 规格 |
## 文档检查与重要缺口
当前分册对首期范围与工程方向的描述已对齐,但行为、数据、素材与接口仍存在施工缺口。局部算术推算不能代替完整数值验算,也不代表策划案已通过验收。
| 相关分册 | 重要缺口 | 详细位置 |
|---|---|---|
| 01、03 | 时间、体力、天气、跨日结算与存档恢复未完整定义 | 01 待解决问题、03 用已知数值做局部验算及待解决问题 |
| 01、02、03 | 基础采集、地图配置及其素材绑定不完整 | 各分册的采集、地图与待解决问题 |
| 01、03 | 背包容量、交易边界、成长曲线及当前范围全量数据不足 | 01 S07/S08/S09、03 配置与缺口 |
| 01、02 | 素材清单、帧与地块映射、字体和双视口布局尚待补齐 | 02 待解决问题、01 场景与交互 |
策划案验收要求补齐这些正文、检查跨分册一致性和必要验算,使施工方仅凭本套 TDD 能完成当前范围。素材可以在文档完成后按规格制作,游戏构建、接入和试玩按分册计划执行;没有执行的检查不写成已通过。
详细问题只在对应分册维护,解决后更新正文并移出本汇总。
当前无任何 blocker:填数(03)、扩产(02)、v0.1 联调(01)三线并行合法。B 级第 1 条(背包容量)在 v0.1 存档实现前必须收口,否则冻结存档模块。

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