diff --git a/.gitignore b/.gitignore
index b1429b9..0590544 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,9 +24,6 @@ __pycache__/
# Approved, versioned brand resources are package source assets.
!packages/brand/assets/**/*.png
!packages/brand/docs/logo-preview.png
-/apps/studio/public/brand/
-/apps/studio/public/favicon.ico
-/apps/studio/public/apple-touch-icon.png
/apps/dashboard/public/brand/
/apps/dashboard/public/favicon.ico
/apps/dashboard/public/apple-touch-icon.png
diff --git a/apps/dashboard/ACCOUNT.md b/apps/dashboard/ACCOUNT.md
index 6f49425..e004ee1 100644
--- a/apps/dashboard/ACCOUNT.md
+++ b/apps/dashboard/ACCOUNT.md
@@ -1,6 +1,7 @@
# Email accounts
-`/account` offers registration, password login, email verification/resend, and logout.
+`/account` offers registration, password login, email verification/resend, password
+recovery, and logout.
`/api/account/session` returns the current account; other actions use same-origin POST.
Passwords require at least 12 characters and at most 256 UTF-8 bytes. Only verified
accounts can log in. Verification links expire after 30 minutes and are consumed once.
@@ -9,24 +10,22 @@ Only token SHA-256 digests are stored. Passwords use individually salted scrypt.
## Runtime configuration
-The existing production deployment reads `/etc/prompt.env` on ces-control. Set its
-ownership to root and mode to 0600. The operator should update SMTP_PASSWORD there
-through a secure remote session, without putting it in command arguments, repository,
-CI output, release.env, or chat. Existing compose deployment reads this file without
-copying credentials into the release directory. Do not run `docker compose config`
-without `--quiet` against the production environment because interpolation shows secrets.
-Docker administrators can inspect container environment; access to Docker is privileged.
+Use [the environment example](.env.example) and the root README to configure the Web,
+bootstrap, and worker processes. The repository no longer supplies CI/CD or Compose
+deployment configuration. Keep SMTP_PASSWORD and other credentials in the process
+environment or an operator-managed private file with restricted permissions, outside
+the repository. Do not put credentials in command arguments, logs, or chat.
-Set ACCOUNT_PUBLIC_ORIGIN to the exact browser origin and SMTP_HOST=smtpdm.aliyun.com,
-SMTP_PORT=465, SMTP_USERNAME and SMTP_FROM=noreply@notice.entroia.com. TLS certificate
+Set ACCOUNT_PUBLIC_ORIGIN to the exact browser origin and configure SMTP_HOST,
+SMTP_PORT, SMTP_USERNAME, SMTP_FROM, and SMTP_PASSWORD for the mail provider. TLS certificate
validation stays enabled. Missing SMTP configuration returns a generic service failure;
resend with the registration password can recover an account whose initial delivery failed.
Keep AUTH_CONFIG_FILE configured for administrator access. Missing administrator
configuration fails closed. AUTH_DISABLED_FOR_TESTS is false by default and is enabled
-only by the disposable legacy integration stack; never enable it in production.
+only for an explicitly isolated test environment; never enable it in production.
Email account cookies never satisfy administrator authorization. With the current HTTP
-acceptance origin use AUTH_COOKIE_SECURE=false; use true after enabling HTTPS.
+runtime origin use AUTH_COOKIE_SECURE=false; use true for HTTPS.
Limits persist in PostgreSQL: 10 logins and 3 registration/resend attempts per email per
15 minutes, plus 300 requests per 15 minutes globally. ACCOUNT_TRUST_PROXY defaults
@@ -37,13 +36,16 @@ response for existing/unknown emails, and login uses a dummy KDF for unknown acc
The rate limit itself can reveal recent activity for a known email; it does not reveal
whether an account exists. Synchronous SMTP latency can still expose a timing side channel;
a durable asynchronous mail queue would be needed to fully decouple delivery timing.
-Logout remains available when login/mail limits are exhausted. No password recovery or
-account deletion is included.
+Logout remains available when login/mail limits are exhausted. Password recovery uses
+a single-use reset link that expires after 30 minutes; resetting the password revokes
+existing sessions. Account deletion is not included.
## Verification
-ces-control runs crypto/origin tests, PostgreSQL verification-token replay races,
-expired/revoked sessions, concurrent limit consumption and unverified login rejection.
-Production-auth exercises verify that account cookies cannot authorize legacy writes.
-Actual SMTP delivery and visual acceptance at http://8.211.154.134:18131/account require
-operator runtime configuration and the normal manually approved deployment.
+There is no automatic verification pipeline. Turbo dry-runs only verify task planning;
+they do not exercise account behavior. Runtime verification requires an explicitly
+authorized environment with PostgreSQL and SMTP configuration. Cover token replay,
+expired/revoked sessions, concurrent limits, password recovery, and rejection of
+unverified logins. Verify separately that account cookies cannot authorize administrator
+writes, that real email is delivered, and that the account page works in a browser.
+Report the checks actually executed; merging into `dev` does not deploy the application.
diff --git a/apps/dashboard/src/components/Brand.tsx b/apps/dashboard/src/components/Brand.tsx
index 180ae51..ab0e070 100644
--- a/apps/dashboard/src/components/Brand.tsx
+++ b/apps/dashboard/src/components/Brand.tsx
@@ -1,4 +1,4 @@
-/** The approved mark is copied from @endoleap/brand during the remote build. */
+/** The approved mark is copied from @endoleap/brand by brand:prepare. */
export function Brand({ compact = false, markOnly = false }: { compact?: boolean; markOnly?: boolean }) {
return 
{!markOnly && 啡跃{!compact && Endoleap}};
}
diff --git a/apps/dashboard/src/lib/studio-design-documentation.ts b/apps/dashboard/src/lib/studio-design-documentation.ts
index e332630..6077d96 100644
--- a/apps/dashboard/src/lib/studio-design-documentation.ts
+++ b/apps/dashboard/src/lib/studio-design-documentation.ts
@@ -1,4 +1,4 @@
import type {NextApiRequest,NextApiResponse} from 'next';
-export const designDocs="# Studio 排版 API · 标准图文与 27 套固定构图\n\n把本篇与图片生成文档一起交给 coding agent。agent 自行选择图片、配色、字体、构图与参数,通过 HTTP 保存渲染描述,得到可持续更新的原生 HTML/CSS 页面。数据库只保存模板关联、文字、素材引用和渲染参数,不保存截图或任意 HTML。\n\n[可选:查看模板示例](/studio) · [读取实时 API 契约](/api/studio/designs?agent_mode=True) · [照片入皮影](/explore/3c98946754c33309d73d5284) · [街头小人](/explore/4ce3283fd98bb03a8fb39a19)\n\n## agent 的交付流程\n\n1. 按下文读取模板 API,选择 layoutId,并获取该模板实际的 T/I/D 元素 ID。\n2. 上传图片取得 assetId,把图片、文字和参数提交给创建 API。\n3. 从创建响应读取 `design.id` 与 `design.url`,把完整结果链接交给用户,例如 `http://8.211.154.134:18131/studio/template-layout?id=实际返回的UUID`。\n4. 用户直接打开该链接看结果;修改内容继续调用 PATCH,同一 ID 与结果链接保持不变。\n\n不要编造 ID,也不要把模板预览链接当作最终结果。API 保存成功并返回真实 UUID 才算完成。以下文档足以通过 HTTP 完成流程,无需使用编辑器。\n\n## 多页作品:从创作 brief 到可发布文件(schemaVersion 2)\n\n多页作品由 coding agent 完成创作决策与图像生成,网站负责封闭参数验证、事务保存与原生渲染。无需模型服务、模型密钥或编辑器。先形成主题、读者、意图、逐页分镜,再生成需要的图片,最后通过 HTTP 保存整组作品。封面、正文、结尾共用一个真实 UUID、修订号和 Wiki post。\n\n### 完整内容与视觉模型\n\n创建 `POST /api/studio/series`,body 为 `{schemaVersion:2,name,document}`。读取/整体修订使用 `GET/PATCH /api/studio/series/{id}`;PATCH 额外提供最新 revision。最大512KB,未知字段会拒绝。document:\n\n- `version:1`:多页文档结构版本。\n- `brief`:topic、audience、intent、designIntent、imageStrategy,均为必填非空文字,最多2000字符。分别说明主题、读者、内容目标、完整设计描述和配图策略。\n- `style.version`:agent 指定的样式版本标识(最多80字符),如 `autumn-journal/1`。它用于记录创作版本;不锁定未来网站渲染器,精确交付请同时保留导出文件和 manifest。\n- `style.palette`:paper、ink、muted、accent,均为 #RRGGBB。\n- `style.typography`:title、body、caption 三种层级,每项包含 fontFamily(sans/serif/mono)、fontSize(0.1–40)、fontWeight(100–900)、lineHeight(0.5–4)、letterSpacing(-5–10)。字号和字距以120宽参考画板为单位,固定模板按画板宽度同比换算。\n- `style.spacing`:margin(4–16)、gap(1–10),并要求 `2*margin+4*gap<=48`。标准排版据此计算标题、图片、正文和分隔线的位置;固定模板保留原构图,用 layers 显式调整位置。\n- `sources`:最多100项,每项 assetId、author、license、url、prompt、tool 全部必填,文字最多4000字符。url 是 http(s) 来源地址或 `generated`。用户照片记录来源与授权;生成图记录完整提示词和工具,不把 AI 图写成摄影原作。所有被页面引用的图片必须有来源记录。\n- `pages`:本工作流支持3–18页(这是本服务的约束,不宣称是平台实时上限)。每页 key 唯一(小写字母/数字/连字符,最多60位)、role(首项 cover,中间 body,末项 ending)、layoutId、intent(最多1000字符)、bindings、parameters。parameters 继续使用下文封闭的单页参数契约。\n- `pages[].bindings`:把实际文字元素 ID 映射到 title/body/caption,例如 `{T01:\"title\",T02:\"body\",T03:\"caption\"}`。被绑定元素必须提供文案。共享字体、墨色和纸色会参与真实渲染;单元素显式值优先覆盖。所有可见文字必须提供或明确隐藏,避免默认占位文案泄漏。图片默认色与装饰默认色取 accent。\n\n标准排版可直接沿用 T01/T02/T03/I01/D01;固定排版先读对应模板 API,元素不能混用。agent 必须控制标题长度和正文密度,不能把“已保存”当成“已验收”。同组图片建议统一比例;导出器遇到混合比例会拒绝,agent 应改用同一画板并调整内容布局。\n\n### 一次保存,一条直接结果链接\n\n```sh\n# series.json 包含完整 document,请按下文契约构造\ncurl -fsS -X POST \"$BASE/api/studio/series\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' \\\n --data-binary @series.json\n# 返回 {design}:schemaVersion=2、document、id、revision、url、postId 等\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \"$BASE/api/studio/series/$ID\"\n```\n\n创建响应的 `design.url` 仍是 `/studio/template-layout?id={UUID}`;直接展示全部页,无需选模板。`&page=2` 只显示第2页,非法页码返回404。页面是服务端原生文字与 CSS,图片走 /api/preview。创建与全部页验证、Wiki post 处于同一事务,任一页无效整组不保存。PATCH 整体替换 document,revision 冲突返回409;先重新读取并合并。单页 PATCH 接口会拒绝修改多页作品,避免只改封面导致组内不一致。可从 designs 列表发现作品,schemaVersion 区分1与2。\n\n归档 `DELETE /api/studio/series/{id}` body `{revision}`;恢复 `POST` 同一路径 body `{revision,archived:false}`。归档后结果页和导出计划返回404,API 仍能读取并恢复;参数、素材和 Wiki post 保留。更新复用原 Wiki post,手工编辑过的正文不被覆盖。\n\n### 高质量导出与验收\n\n`GET /api/studio/series/{id}/export` 返回固定顺序的导出计划:id、revision、每页 key/role/number、filename、width/height、原生渲染 url。计划本身不生成位图。示例统一为3:4、1080×1440 PNG;其他固定模板保留自己的画板比例,不拉伸。该尺寸是本流程的交付规格;发布前还须在小红书当前发布界面复核裁切及文件限制,本站不自动发布。\n\n导出 URL 带 `&page=N&export=1`,画布在1080 CSS像素下重新布局原生文字,不把860宽或手机截图放大。图片使用 `/api/preview?source=...&width=2160&profile=export`:WebP质量95,不为常规缩略图预算降低尺寸,不放大小原件。普通展示仍使用240/480/960/1280及100KB/220KB预算。\n\n在用户已确认的 **ces-control / aliyun-ces-control** 上运行仓库 `scripts/export-studio-series.cjs`,使用既有测试镜像的 playwright-core、sharp、Chromium 和中文字体。只访问 `http://8.211.154.134:18131`,认证保留进程内。设置 STUDIO_DESIGN_ID、STUDIO_EXPORT_DIR、AUTH_CONFIG_FILE(或由现有登录方式提供的 PROMPT_TOKEN),不在命令行或文件中存令牌。不得在用户本机启动编译、容器构建或预览服务器。\n\n脚本逐页检查字体和图片加载、文字溢出、图片原生分辨率与裁切缩放、相同画板比例、页序、最终PNG像素、导出前后revision一致;记录实际字体、SHA256及manifest。额外生成桌面1200宽和手机390宽整组截图供视觉检查。自动检查通过后,agent 仍须逐页看PNG,核对中文缺字、主体裁切、阅读顺序、留白和系列一致性。检查失败修订 document,重新导出;不能把失败文件当成可发布结果。\n\n最终交付:真实设计结果链接、按01/02/03排序的PNG、完整design.json、manifest.json、素材来源与提示词、简短发布文案。生成图、保存成功、导出成功、人工视觉通过、PR待合并、线上部署验收应分别如实报告。未合并代码的能力不可写成线上已可用。\n\n### 可复现三页示例\n\n使用真实素材时,先上传取得 assetId,再将 UUID 加入对应页的图片位,并在 sources 记录来源。\n\n推荐在 ces-control 的仓库目录直接执行 `bash scripts/deliver-studio-series.sh /absolute/path/series.json /absolute/path/ginkgo-master.png /absolute/path/provenance.json /absolute/path/output-directory`:该脚本复用已部署认证卷和匹配的CI镜像,依次保存、导出并留下证据,不启动构建或部署。成品位于 output-directory/revision-N/;已成功导出的修订会核对哈希后复用,后续修订使用新目录,避免覆盖或混入旧页。\n\n底层保存命令 `node /app/auth-cli.cjs run /delivery/scripts/save-studio-series.mjs /absolute/path/series.json /absolute/path/ginkgo-master.png /absolute/path/provenance.json /absolute/path/output-directory` 经既有 auth-cli run 在远程执行,上传素材并填写所有页面引用后,保存真实作品,写出请求、响应和状态文件。重复运行会读取已保存状态,防止在成功后重复创建;出现网络结果不明时先核对素材/设计列表,不盲目重试。脚本仅在传入文件后写入作品,不自动发布到小红书。\n\n\n## 两类排版,同一内容模型\n\n- **标准排版**:`standard-01`,120×160 单位。沿用原 Studio 图文页的标题、正文、栏目结构,增加主题图片与分隔线。T01 主标题、T02 正文、T03 栏目、I01 图片、D01 分隔线。所有内容和位置可设置,也能增加原生元素。\n- **固定排版**:`ref-01` 至 `ref-27`,保留各自画板、出血、圆形、斜切、竖题和字体构图。先读取模板,按实际 T/I/D ID 填入内容。不能假定各模板拥有相同元素。\n\n两类单页都使用 `/api/studio/designs` 的真实 CRUD。创建额外指定 layoutId;更新从 URL 确定 ID,模板关联不能修改。更换模板应创建新记录,避免把旧元素 ID 错套到新模板。调用方无需打开 `/studio` 或操作编辑器。模板由 agent 经 API 选择,图片和文字由 API 保存,用户只打开结果链接。现有独立工具箱功能保持可用。\n\n## 1. 由 agent 通过 API 发现模板\n\n以下 curl 使用指定服务器。`PROMPT_TOKEN` 由用户通过现有登录方式提供,只保存在进程环境,不放 URL 或日志。也可使用已登录浏览器的同源 Cookie;浏览器写请求需要同源 Origin。未登录 API 返回 401。\n\n```sh\nBASE=http://8.211.154.134:18131\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \"$BASE/studio/api/layouts\"\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \"$BASE/studio/api/layouts/standard-01\"\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \"$BASE/studio/api/layouts/ref-17\"\n```\n\n目录返回 `version, layouts, saveApi, catalogUrl, documentationUrl`。每项包含 `id,name,family,url,api`,family 为 standard/fixed。模板返回尺寸、元素 ID/类型/role/box/direction/text、默认 parameters、workspaceSchema 与页面 URL。`?agent_mode=True` 返回纯文本文档,业务请求移除此参数。\n\n## 2. 生成图片,上传一次,显示压缩衍生图\n\n先让 coding agent 按生成图片文档产出文件;Studio 不暗中调用生成模型。图片可以来自用户素材或生成结果。上传走现有素材 API:\n\n```sh\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \\\n -F kind=image -F assetOnly=true -F files=@hero.png \"$BASE/api/upload\"\n```\n\n返回 `assets` UUID 数组及对应 `files` 元数据。取 `assets[0]` 作为 assetId。上传不单独发帖;设计创建时才自动关联 Wiki post。不要把 Base64、任意远程 URL、HTML 或 SVG 塞入参数。\n\n原素材保留在素材库,**页面展示只请求压缩 WebP**。以 assetId 引用素材,不必自行再上传缩略图:\n\n```sh\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \\\n \"$BASE/api/preview?source=%2Fapi%2Fmedia%2FASSET_UUID&width=960\" -o hero-preview.webp\n```\n\nwidth 只允许 240/480/960/1280;小图预算 100KB,大图预算 220KB,复杂图片会降低尺寸/质量。原生页面按槽位显示宽度和像素密度选择 srcset 衍生图,保留 fit/cropX/cropY/zoom。目录使用原生文字与 CSS 色块,不加载参考原图;旧工具箱参考图也使用压缩预览。`/api/media/{id}` 是素材原件读取接口,不应用作展示图片的 src。\n\n## 3. 创建:POST /api/studio/designs\n\n创建和更新共用内容字段 `name,parameters`;`schemaVersion` 可省略,单页当前支持 1(多页使用上述独立 series API 的2)。创建额外传 `layoutId`,不传 revision 或 id。\n\n```sh\ncurl -fsS -X POST \"$BASE/api/studio/designs\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' \\\n -d '{\"schemaVersion\":1,\"layoutId\":\"standard-01\",\"name\":\"观察日常\",\"parameters\":{\"paper\":\"#edf0ef\",\"texts\":{\"T01\":{\"value\":\"观察日常\\n记录灵感\",\"fontFamily\":\"serif\",\"color\":\"#23424b\"},\"T02\":{\"value\":\"让每一页只讲一件事。\",\"lineHeight\":1.4}},\"images\":{\"I01\":{\"color\":\"#73929a\",\"fit\":\"cover\",\"cropX\":50,\"cropY\":45,\"zoom\":1}},\"decorations\":{\"D01\":{\"color\":\"#73929a\"}}}}'\n```\n\n有图片时在 I01 加 `assetId:\"上传返回的UUID\"`。固定排版只需改为所选 `layoutId`,并按 schema 选择元素 ID。例如 ref-01 支持 `texts.T01`、`texts.T02` 与 `images.I01`。\n\n201 返回 `{design}`。design 包含:\n\n| 字段 | 含义 |\n| --- | --- |\n| id / layoutId / family | 持久化 UUID、不可变模板 ID、standard 或 fixed |\n| schemaVersion / revision | 参数契约版本(1)、记录修订号(从1递增) |\n| name / parameters | 名称与规范化内容;省略的分组返回空对象 |\n| url / renderUrl | 同一个原生 HTML/CSS 页面 URL |\n| schemaUrl | 当前模板参数地址 |\n| postId / postUrl | 自动创建并在后续更新中复用的 Wiki post |\n| archived / archivedAt | 可恢复归档状态与时间 |\n| createdAt / updatedAt | 创建与最后修改时间 |\n| legacySvgUrl | 固定排版的旧 SVG 导出地址,标准排版为 null |\n\n创建设计与 Wiki post 在同一数据库事务内完成,失败整体回滚。更新同一设计复用同一 post;手工编辑过的 Wiki 正文、标题、标签、封面不会被参数更新覆盖。\n\n## 4. 读取与打开\n\n```sh\nID=创建返回的UUID\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \"$BASE/api/studio/designs/$ID\"\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \"$BASE/api/studio/designs?layoutId=standard-01&limit=20\"\n```\n\n读取返回 `{design}`,没有副作用。列表默认只列未归档记录;`archived=true` 只列归档记录;limit 为1–50,默认20;`nextCursor` 作为下一页 before。layoutId 可省略。\n\n直接打开创建响应中的 `design.url`:`/studio/template-layout?id={UUID}`。这个 UUID 对应数据库里 API 保存的模板、图片与文字,服务端按记录渲染最终 HTML/CSS。链接中无需携带 layoutId,无需打开 `/studio` 选择模板,也没有编辑按钮、双击编辑或右键编辑。`standard-01` 与 `ref-17` 是模板 ID,不是保存记录的 UUID。\n\n`/studio/designs/{UUID}` 与旧 `/studio/layouts/{layoutId}?id={UUID}` 兼容跳转到同一个结果页。缺失、非法、不存在或已归档的 ID 返回404,不会显示空模板或编辑器;旧链接模板与记录不匹配也返回404。归档设计仍能经 API 读取以恢复。\n\n## 5. 更新:PATCH /api/studio/designs/{id}\n\n先 GET,保留所有未改字段,再整体替换 parameters;不是深度合并。以下假设刚读到 revision=1:\n\n```sh\ncurl -fsS -X PATCH \"$BASE/api/studio/designs/$ID\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' \\\n -d '{\"name\":\"观察日常 · 修订\",\"revision\":1,\"parameters\":{\"texts\":{\"T01\":{\"value\":\"新的标题\"}},\"images\":{},\"decorations\":{}}}'\n```\n\n200 返回新 design,revision 增加。过期 revision 返回409,重新 GET 并合并后再提交;不要盲目重试。不接受 layoutId、id、url、postId 等返回字段;不能直接把整个 design 作为 body。另存副本使用 POST 创建新 UUID。\n\n## 6. 删除与恢复\n\nDELETE 采用可恢复归档,不物理删除参数、素材或 Wiki post。和更新一样必须提供最新 revision;自动同步关联 post 的归档状态。\n\n```sh\ncurl -fsS -X DELETE \"$BASE/api/studio/designs/$ID\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' -d '{\"revision\":2}'\n# 删除后读取新 revision,再恢复。此例删除后为3:\ncurl -fsS -X POST \"$BASE/api/studio/designs/$ID\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' -d '{\"revision\":3,\"archived\":false}'\n```\n\n两者200返回 `{design}`,revision 递增。归档记录 PATCH 返回409,先恢复。重复写入仍需最新 revision;409不会修改数据。独立归档 Wiki post 只影响笔记发现状态,不等于删除设计。旧设计缺 Wiki 入口可调用 `POST /api/studio/designs/{id}/post`,body `{}`,首次201、已有200;不改变 revision。\n\n## 参数清单(两类共用)\n\nparameters 顶层允许 texts/images/decorations/paper/layers/added;全部可省略,不能添加未知字段。最大请求64KB。颜色都为 `#RRGGBB`。坐标与字号使用模板单位,不是 CSS 像素。\n\n| 分组 | 字段与约束 |\n| --- | --- |\n| texts.{文字ID} | value 必填,可空,最多500字/8行;color;scale 0.25–2;align start/middle/end;fontFamily sans/serif/mono;fontSize 0.1–1000;fontWeight 100–900;lineHeight 0.5–4;letterSpacing -20–100 |\n| images.{图片ID} | assetId(已存在的图片 UUID);color;fit cover/contain;cropX/cropY 0–100(默认50);zoom 1–5(默认1) |\n| decorations.{装饰ID} | color;hidden 布尔值 |\n| paper | 纸张颜色 |\n| layers.{元素ID} | x/y -10000–10000;width/height 0.1–10000;rotation -360–360;opacity 0–1;radius 0–5000;z -1000–1000;hidden/locked 布尔值 |\n| added | 最多100项:id 为 user- 加1–60位字母/数字/连字符,唯一;kind text/image/decoration;role 最多80字;box 为 [x,y,width,height];direction 必须 horizontal;text 为文字或null;reading 必须 custom;装饰可带 shape rectangle/ellipse |\n\n新增元素先在 added 声明,然后在 texts/images/decorations/layers 用该 ID 配置。locked 控制工作区交互,不禁止 agent 更新。数据是封闭结构,无脚本执行。未来扩展新增契约版本;v1 不接受未知字段/版本。现有省略 schemaVersion 的请求继续按v1处理,旧记录无需重建,布局 ID 和页面 UUID 保持不变。默认视觉可随模板美化变化;要求固定外观时显式设置配色、字体和图层参数。\n\n错误:400 参数/版本/构件类型/图片 ID 不合法;401 未登录;404 模板或设计不存在;409 修订冲突或已归档;405 方法不支持;413 请求超限;500 服务失败。压缩预览失败可能返回503与 Retry-After。\n\n## 现有工具箱与兼容导出\n\n工具功能保留:[ref-17 同一母版四张试版](/studio/ideas/learning-skills-template)、[ref-01/07/26 三种构图试版](/studio/ideas/layout-selection)、[最初图文页](/studio/ideas/first-idea)。旧封面工具文档已合并到本篇,旧文档 URL 保留为归档说明,避免重复顶级入口。\n\n旧无状态 API:`/studio/api/export/learning-skills-template` 和 `/studio/api/export/layout-selection` 支持 GET/POST,不保存设计。前者参数 slide=0..3、heading(1–6字)、body(最多360字/3行)、color/accent、masthead(2项);后者 layoutId=ref-01/ref-07/ref-26、fields(对应T ID,1–120字/4行)、color/accent。GET 默认返回方案 JSON;GET format=svg 导出初始图;POST format=svg(默认)导出 SVG,format=json 返回参数,最大32KB。first-idea 仅支持 GET 方案/Markdown。\n\n```sh\ncurl -fsS -X POST \"$BASE/studio/api/export/learning-skills-template?format=svg\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' \\\n -d '{\"slide\":1,\"heading\":\"笔记复习\",\"color\":\"#7a8b7e\"}' -o cover.svg\ncurl -fsS -X POST \"$BASE/studio/api/export/layout-selection?format=svg\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' \\\n -d '{\"layoutId\":\"ref-01\",\"fields\":{\"T01\":\"STUDY\"},\"color\":\"#83918a\"}' -o selection.svg\n```\n\n固定排版 `/studio/api/layouts/ref-01` 的 GET format=svg、POST 仍提供旧分层 SVG;POST format=json 只验证和返回规范化参数。**旧 SVG 不反映 added、layers、扩展字体和裁切参数**,不能用来证明原生效果。standard-01 不支持 SVG。原生页面应直接打开返回 URL,;多页可按上文通过导出器生成PNG。代码可扩展渲染能力,但每次是否使用、选择哪些参数均由 coding agent 决定。\n\n## 固定排版索引\n\n读取 /studio/api/layouts 获取全部27套构图。\n";
+export const designDocs="# Studio 排版 API · 标准图文与 27 套固定构图\n\n把本篇与图片生成文档一起交给 coding agent。agent 自行选择图片、配色、字体、构图与参数,通过 HTTP 保存渲染描述,得到可持续更新的原生 HTML/CSS 页面。数据库只保存模板关联、文字、素材引用和渲染参数,不保存截图或任意 HTML。\n\n[可选:查看模板示例](/studio) · [读取实时 API 契约](/api/studio/designs?agent_mode=True) · [照片入皮影](/explore/3c98946754c33309d73d5284) · [街头小人](/explore/4ce3283fd98bb03a8fb39a19)\n\n## agent 的交付流程\n\n1. 按下文读取模板 API,选择 layoutId,并获取该模板实际的 T/I/D 元素 ID。\n2. 上传图片取得 assetId,把图片、文字和参数提交给创建 API。\n3. 从创建响应读取 `design.id` 与 `design.url`,把完整结果链接交给用户,例如 `http://8.211.154.134:18131/studio/template-layout?id=实际返回的UUID`。\n4. 用户直接打开该链接看结果;修改内容继续调用 PATCH,同一 ID 与结果链接保持不变。\n\n不要编造 ID,也不要把模板预览链接当作最终结果。API 保存成功并返回真实 UUID 才算完成。以下文档足以通过 HTTP 完成流程,无需使用编辑器。\n\n## 多页作品:从创作 brief 到可发布文件(schemaVersion 2)\n\n多页作品由 coding agent 完成创作决策与图像生成,网站负责封闭参数验证、事务保存与原生渲染。无需模型服务、模型密钥或编辑器。先形成主题、读者、意图、逐页分镜,再生成需要的图片,最后通过 HTTP 保存整组作品。封面、正文、结尾共用一个真实 UUID、修订号和 Wiki post。\n\n### 完整内容与视觉模型\n\n创建 `POST /api/studio/series`,body 为 `{schemaVersion:2,name,document}`。读取/整体修订使用 `GET/PATCH /api/studio/series/{id}`;PATCH 额外提供最新 revision。最大512KB,未知字段会拒绝。document:\n\n- `version:1`:多页文档结构版本。\n- `brief`:topic、audience、intent、designIntent、imageStrategy,均为必填非空文字,最多2000字符。分别说明主题、读者、内容目标、完整设计描述和配图策略。\n- `style.version`:agent 指定的样式版本标识(最多80字符),如 `autumn-journal/1`。它用于记录创作版本;不锁定未来网站渲染器,精确交付请同时保留导出文件和 manifest。\n- `style.palette`:paper、ink、muted、accent,均为 #RRGGBB。\n- `style.typography`:title、body、caption 三种层级,每项包含 fontFamily(sans/serif/mono)、fontSize(0.1–40)、fontWeight(100–900)、lineHeight(0.5–4)、letterSpacing(-5–10)。字号和字距以120宽参考画板为单位,固定模板按画板宽度同比换算。\n- `style.spacing`:margin(4–16)、gap(1–10),并要求 `2*margin+4*gap<=48`。标准排版据此计算标题、图片、正文和分隔线的位置;固定模板保留原构图,用 layers 显式调整位置。\n- `sources`:最多100项,每项 assetId、author、license、url、prompt、tool 全部必填,文字最多4000字符。url 是 http(s) 来源地址或 `generated`。用户照片记录来源与授权;生成图记录完整提示词和工具,不把 AI 图写成摄影原作。所有被页面引用的图片必须有来源记录。\n- `pages`:本工作流支持3–18页(这是本服务的约束,不宣称是平台实时上限)。每页 key 唯一(小写字母/数字/连字符,最多60位)、role(首项 cover,中间 body,末项 ending)、layoutId、intent(最多1000字符)、bindings、parameters。parameters 继续使用下文封闭的单页参数契约。\n- `pages[].bindings`:把实际文字元素 ID 映射到 title/body/caption,例如 `{T01:\"title\",T02:\"body\",T03:\"caption\"}`。被绑定元素必须提供文案。共享字体、墨色和纸色会参与真实渲染;单元素显式值优先覆盖。所有可见文字必须提供或明确隐藏,避免默认占位文案泄漏。图片默认色与装饰默认色取 accent。\n\n标准排版可直接沿用 T01/T02/T03/I01/D01;固定排版先读对应模板 API,元素不能混用。agent 必须控制标题长度和正文密度,不能把“已保存”当成“已验收”。同组图片建议统一比例;导出器遇到混合比例会拒绝,agent 应改用同一画板并调整内容布局。\n\n### 一次保存,一条直接结果链接\n\n```sh\n# series.json 包含完整 document,请按下文契约构造\ncurl -fsS -X POST \"$BASE/api/studio/series\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' \\\n --data-binary @series.json\n# 返回 {design}:schemaVersion=2、document、id、revision、url、postId 等\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \"$BASE/api/studio/series/$ID\"\n```\n\n创建响应的 `design.url` 仍是 `/studio/template-layout?id={UUID}`;直接展示全部页,无需选模板。`&page=2` 只显示第2页,非法页码返回404。页面是服务端原生文字与 CSS,图片走 /api/preview。创建与全部页验证、Wiki post 处于同一事务,任一页无效整组不保存。PATCH 整体替换 document,revision 冲突返回409;先重新读取并合并。单页 PATCH 接口会拒绝修改多页作品,避免只改封面导致组内不一致。可从 designs 列表发现作品,schemaVersion 区分1与2。\n\n归档 `DELETE /api/studio/series/{id}` body `{revision}`;恢复 `POST` 同一路径 body `{revision,archived:false}`。归档后结果页和导出计划返回404,API 仍能读取并恢复;参数、素材和 Wiki post 保留。更新复用原 Wiki post,手工编辑过的正文不被覆盖。\n\n### 高质量导出与验收\n\n`GET /api/studio/series/{id}/export` 返回固定顺序的导出计划:id、revision、每页 key/role/number、filename、width/height、原生渲染 url。计划本身不生成位图。示例统一为3:4、1080×1440 PNG;其他固定模板保留自己的画板比例,不拉伸。该尺寸是本流程的交付规格;发布前还须在小红书当前发布界面复核裁切及文件限制,本站不自动发布。\n\n导出 URL 带 `&page=N&export=1`,画布在1080 CSS像素下重新布局原生文字,不把860宽或手机截图放大。图片使用 `/api/preview?source=...&width=2160&profile=export`:WebP质量95,不为常规缩略图预算降低尺寸,不放大小原件。普通展示仍使用240/480/960/1280及100KB/220KB预算。\n\n当前仓库不提供自动 PNG 导出脚本,也不配置 CI/CD 或固定 runner。先调用 `GET /api/studio/series/{id}/export` 读取实际导出计划,再在用户授权的运行环境中使用浏览器逐页打开计划返回的原生渲染 URL,按计划画板尺寸导出。字体、图片加载与认证由该环境准备;不要把导出计划 API 的成功当成已经生成 PNG。认证信息仅保留在进程内,不写入命令行、日志或交付文件。\n\n导出时逐页检查字体和图片加载、文字溢出、图片原生分辨率与裁切缩放、相同画板比例、页序、最终PNG像素、导出前后revision一致;记录实际字体、SHA256及manifest。额外生成桌面1200宽和手机390宽整组截图供视觉检查。自动检查通过后,agent 仍须逐页看PNG,核对中文缺字、主体裁切、阅读顺序、留白和系列一致性。检查失败修订 document,重新导出;不能把失败文件当成可发布结果。\n\n最终交付:真实设计结果链接、按01/02/03排序的PNG、完整design.json、manifest.json、素材来源与提示词、简短发布文案。生成图、保存成功、导出成功、人工视觉通过、PR待合并、线上部署验收应分别如实报告。未合并代码的能力不可写成线上已可用。\n\n### 保存与导出记录\n\n使用真实素材时,先上传取得 assetId,再将 UUID 加入对应页的图片位,并在 sources 记录来源。\n\n保存作品使用本篇的 HTTP API;仓库不再包含旧的 `deliver-studio-series.sh` 一键交付脚本。每次成功保存后记录真实设计 ID、revision、上传素材 ID 和原始请求;若写入的网络结果不明,先核对素材与设计列表,避免盲目重复创建。\n\n按 revision 为每次导出建立独立输出目录,保留 design.json、素材来源、逐页 PNG 和校验清单;复用旧导出前核对其 revision 与文件哈希,避免混入不同修订的页面。保存作品和导出文件均不自动发布到小红书。\n\n\n## 两类排版,同一内容模型\n\n- **标准排版**:`standard-01`,120×160 单位。沿用原 Studio 图文页的标题、正文、栏目结构,增加主题图片与分隔线。T01 主标题、T02 正文、T03 栏目、I01 图片、D01 分隔线。所有内容和位置可设置,也能增加原生元素。\n- **固定排版**:`ref-01` 至 `ref-27`,保留各自画板、出血、圆形、斜切、竖题和字体构图。先读取模板,按实际 T/I/D ID 填入内容。不能假定各模板拥有相同元素。\n\n两类单页都使用 `/api/studio/designs` 的真实 CRUD。创建额外指定 layoutId;更新从 URL 确定 ID,模板关联不能修改。更换模板应创建新记录,避免把旧元素 ID 错套到新模板。调用方无需打开 `/studio` 或操作编辑器。模板由 agent 经 API 选择,图片和文字由 API 保存,用户只打开结果链接。现有独立工具箱功能保持可用。\n\n## 1. 由 agent 通过 API 发现模板\n\n以下 curl 使用指定服务器。`PROMPT_TOKEN` 由用户通过现有登录方式提供,只保存在进程环境,不放 URL 或日志。也可使用已登录浏览器的同源 Cookie;浏览器写请求需要同源 Origin。未登录 API 返回 401。\n\n```sh\nBASE=http://8.211.154.134:18131\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \"$BASE/studio/api/layouts\"\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \"$BASE/studio/api/layouts/standard-01\"\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \"$BASE/studio/api/layouts/ref-17\"\n```\n\n目录返回 `version, layouts, saveApi, catalogUrl, documentationUrl`。每项包含 `id,name,family,url,api`,family 为 standard/fixed。模板返回尺寸、元素 ID/类型/role/box/direction/text、默认 parameters、workspaceSchema 与页面 URL。`?agent_mode=True` 返回纯文本文档,业务请求移除此参数。\n\n## 2. 生成图片,上传一次,显示压缩衍生图\n\n先让 coding agent 按生成图片文档产出文件;Studio 不暗中调用生成模型。图片可以来自用户素材或生成结果。上传走现有素材 API:\n\n```sh\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \\\n -F kind=image -F assetOnly=true -F files=@hero.png \"$BASE/api/upload\"\n```\n\n返回 `assets` UUID 数组及对应 `files` 元数据。取 `assets[0]` 作为 assetId。上传不单独发帖;设计创建时才自动关联 Wiki post。不要把 Base64、任意远程 URL、HTML 或 SVG 塞入参数。\n\n原素材保留在素材库,**页面展示只请求压缩 WebP**。以 assetId 引用素材,不必自行再上传缩略图:\n\n```sh\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \\\n \"$BASE/api/preview?source=%2Fapi%2Fmedia%2FASSET_UUID&width=960\" -o hero-preview.webp\n```\n\nwidth 只允许 240/480/960/1280;小图预算 100KB,大图预算 220KB,复杂图片会降低尺寸/质量。原生页面按槽位显示宽度和像素密度选择 srcset 衍生图,保留 fit/cropX/cropY/zoom。目录使用原生文字与 CSS 色块,不加载参考原图;旧工具箱参考图也使用压缩预览。`/api/media/{id}` 是素材原件读取接口,不应用作展示图片的 src。\n\n## 3. 创建:POST /api/studio/designs\n\n创建和更新共用内容字段 `name,parameters`;`schemaVersion` 可省略,单页当前支持 1(多页使用上述独立 series API 的2)。创建额外传 `layoutId`,不传 revision 或 id。\n\n```sh\ncurl -fsS -X POST \"$BASE/api/studio/designs\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' \\\n -d '{\"schemaVersion\":1,\"layoutId\":\"standard-01\",\"name\":\"观察日常\",\"parameters\":{\"paper\":\"#edf0ef\",\"texts\":{\"T01\":{\"value\":\"观察日常\\n记录灵感\",\"fontFamily\":\"serif\",\"color\":\"#23424b\"},\"T02\":{\"value\":\"让每一页只讲一件事。\",\"lineHeight\":1.4}},\"images\":{\"I01\":{\"color\":\"#73929a\",\"fit\":\"cover\",\"cropX\":50,\"cropY\":45,\"zoom\":1}},\"decorations\":{\"D01\":{\"color\":\"#73929a\"}}}}'\n```\n\n有图片时在 I01 加 `assetId:\"上传返回的UUID\"`。固定排版只需改为所选 `layoutId`,并按 schema 选择元素 ID。例如 ref-01 支持 `texts.T01`、`texts.T02` 与 `images.I01`。\n\n201 返回 `{design}`。design 包含:\n\n| 字段 | 含义 |\n| --- | --- |\n| id / layoutId / family | 持久化 UUID、不可变模板 ID、standard 或 fixed |\n| schemaVersion / revision | 参数契约版本(1)、记录修订号(从1递增) |\n| name / parameters | 名称与规范化内容;省略的分组返回空对象 |\n| url / renderUrl | 同一个原生 HTML/CSS 页面 URL |\n| schemaUrl | 当前模板参数地址 |\n| postId / postUrl | 自动创建并在后续更新中复用的 Wiki post |\n| archived / archivedAt | 可恢复归档状态与时间 |\n| createdAt / updatedAt | 创建与最后修改时间 |\n| legacySvgUrl | 固定排版的旧 SVG 导出地址,标准排版为 null |\n\n创建设计与 Wiki post 在同一数据库事务内完成,失败整体回滚。更新同一设计复用同一 post;手工编辑过的 Wiki 正文、标题、标签、封面不会被参数更新覆盖。\n\n## 4. 读取与打开\n\n```sh\nID=创建返回的UUID\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \"$BASE/api/studio/designs/$ID\"\ncurl -fsS -H \"Authorization: Bearer $PROMPT_TOKEN\" \"$BASE/api/studio/designs?layoutId=standard-01&limit=20\"\n```\n\n读取返回 `{design}`,没有副作用。列表默认只列未归档记录;`archived=true` 只列归档记录;limit 为1–50,默认20;`nextCursor` 作为下一页 before。layoutId 可省略。\n\n直接打开创建响应中的 `design.url`:`/studio/template-layout?id={UUID}`。这个 UUID 对应数据库里 API 保存的模板、图片与文字,服务端按记录渲染最终 HTML/CSS。链接中无需携带 layoutId,无需打开 `/studio` 选择模板,也没有编辑按钮、双击编辑或右键编辑。`standard-01` 与 `ref-17` 是模板 ID,不是保存记录的 UUID。\n\n`/studio/designs/{UUID}` 与旧 `/studio/layouts/{layoutId}?id={UUID}` 兼容跳转到同一个结果页。缺失、非法、不存在或已归档的 ID 返回404,不会显示空模板或编辑器;旧链接模板与记录不匹配也返回404。归档设计仍能经 API 读取以恢复。\n\n## 5. 更新:PATCH /api/studio/designs/{id}\n\n先 GET,保留所有未改字段,再整体替换 parameters;不是深度合并。以下假设刚读到 revision=1:\n\n```sh\ncurl -fsS -X PATCH \"$BASE/api/studio/designs/$ID\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' \\\n -d '{\"name\":\"观察日常 · 修订\",\"revision\":1,\"parameters\":{\"texts\":{\"T01\":{\"value\":\"新的标题\"}},\"images\":{},\"decorations\":{}}}'\n```\n\n200 返回新 design,revision 增加。过期 revision 返回409,重新 GET 并合并后再提交;不要盲目重试。不接受 layoutId、id、url、postId 等返回字段;不能直接把整个 design 作为 body。另存副本使用 POST 创建新 UUID。\n\n## 6. 删除与恢复\n\nDELETE 采用可恢复归档,不物理删除参数、素材或 Wiki post。和更新一样必须提供最新 revision;自动同步关联 post 的归档状态。\n\n```sh\ncurl -fsS -X DELETE \"$BASE/api/studio/designs/$ID\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' -d '{\"revision\":2}'\n# 删除后读取新 revision,再恢复。此例删除后为3:\ncurl -fsS -X POST \"$BASE/api/studio/designs/$ID\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' -d '{\"revision\":3,\"archived\":false}'\n```\n\n两者200返回 `{design}`,revision 递增。归档记录 PATCH 返回409,先恢复。重复写入仍需最新 revision;409不会修改数据。独立归档 Wiki post 只影响笔记发现状态,不等于删除设计。旧设计缺 Wiki 入口可调用 `POST /api/studio/designs/{id}/post`,body `{}`,首次201、已有200;不改变 revision。\n\n## 参数清单(两类共用)\n\nparameters 顶层允许 texts/images/decorations/paper/layers/added;全部可省略,不能添加未知字段。最大请求64KB。颜色都为 `#RRGGBB`。坐标与字号使用模板单位,不是 CSS 像素。\n\n| 分组 | 字段与约束 |\n| --- | --- |\n| texts.{文字ID} | value 必填,可空,最多500字/8行;color;scale 0.25–2;align start/middle/end;fontFamily sans/serif/mono;fontSize 0.1–1000;fontWeight 100–900;lineHeight 0.5–4;letterSpacing -20–100 |\n| images.{图片ID} | assetId(已存在的图片 UUID);color;fit cover/contain;cropX/cropY 0–100(默认50);zoom 1–5(默认1) |\n| decorations.{装饰ID} | color;hidden 布尔值 |\n| paper | 纸张颜色 |\n| layers.{元素ID} | x/y -10000–10000;width/height 0.1–10000;rotation -360–360;opacity 0–1;radius 0–5000;z -1000–1000;hidden/locked 布尔值 |\n| added | 最多100项:id 为 user- 加1–60位字母/数字/连字符,唯一;kind text/image/decoration;role 最多80字;box 为 [x,y,width,height];direction 必须 horizontal;text 为文字或null;reading 必须 custom;装饰可带 shape rectangle/ellipse |\n\n新增元素先在 added 声明,然后在 texts/images/decorations/layers 用该 ID 配置。locked 控制工作区交互,不禁止 agent 更新。数据是封闭结构,无脚本执行。未来扩展新增契约版本;v1 不接受未知字段/版本。现有省略 schemaVersion 的请求继续按v1处理,旧记录无需重建,布局 ID 和页面 UUID 保持不变。默认视觉可随模板美化变化;要求固定外观时显式设置配色、字体和图层参数。\n\n错误:400 参数/版本/构件类型/图片 ID 不合法;401 未登录;404 模板或设计不存在;409 修订冲突或已归档;405 方法不支持;413 请求超限;500 服务失败。压缩预览失败可能返回503与 Retry-After。\n\n## 现有工具箱与兼容导出\n\n工具功能保留:[ref-17 同一母版四张试版](/studio/ideas/learning-skills-template)、[ref-01/07/26 三种构图试版](/studio/ideas/layout-selection)、[最初图文页](/studio/ideas/first-idea)。旧封面工具文档已合并到本篇,旧文档 URL 保留为归档说明,避免重复顶级入口。\n\n旧无状态 API:`/studio/api/export/learning-skills-template` 和 `/studio/api/export/layout-selection` 支持 GET/POST,不保存设计。前者参数 slide=0..3、heading(1–6字)、body(最多360字/3行)、color/accent、masthead(2项);后者 layoutId=ref-01/ref-07/ref-26、fields(对应T ID,1–120字/4行)、color/accent。GET 默认返回方案 JSON;GET format=svg 导出初始图;POST format=svg(默认)导出 SVG,format=json 返回参数,最大32KB。first-idea 仅支持 GET 方案/Markdown。\n\n```sh\ncurl -fsS -X POST \"$BASE/studio/api/export/learning-skills-template?format=svg\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' \\\n -d '{\"slide\":1,\"heading\":\"笔记复习\",\"color\":\"#7a8b7e\"}' -o cover.svg\ncurl -fsS -X POST \"$BASE/studio/api/export/layout-selection?format=svg\" \\\n -H \"Authorization: Bearer $PROMPT_TOKEN\" -H 'Content-Type: application/json' \\\n -d '{\"layoutId\":\"ref-01\",\"fields\":{\"T01\":\"STUDY\"},\"color\":\"#83918a\"}' -o selection.svg\n```\n\n固定排版 `/studio/api/layouts/ref-01` 的 GET format=svg、POST 仍提供旧分层 SVG;POST format=json 只验证和返回规范化参数。**旧 SVG 不反映 added、layers、扩展字体和裁切参数**,不能用来证明原生效果。standard-01 不支持 SVG。原生页面应直接打开返回 URL,;多页可按上文通过导出器生成PNG。代码可扩展渲染能力,但每次是否使用、选择哪些参数均由 coding agent 决定。\n\n## 固定排版索引\n\n读取 /studio/api/layouts 获取全部27套构图。\n";
export function studioDesignDocumentation(req:NextApiRequest,res:NextApiResponse){if(!['GET','HEAD'].includes(req.method||'')||String(req.query.agent_mode).toLowerCase()!=='true')return false;res.setHeader('Content-Type','text/plain; charset=utf-8');res.setHeader('Cache-Control','no-store');if(req.method==='HEAD')res.status(200).end();else res.status(200).send(designDocs);return true}
diff --git a/apps/dashboard/src/studio/components/Brand.tsx b/apps/dashboard/src/studio/components/Brand.tsx
index 8a55954..57cc858 100644
--- a/apps/dashboard/src/studio/components/Brand.tsx
+++ b/apps/dashboard/src/studio/components/Brand.tsx
@@ -1,4 +1,4 @@
-/** The approved mark is copied from @endoleap/brand during the remote build. */
+/** The approved mark is copied from @endoleap/brand by brand:prepare. */
export function Brand({ compact = false }: { compact?: boolean }) {
return 
啡跃{!compact && Endoleap};
}
diff --git a/packages/brand/scripts/prepare-app.mjs b/packages/brand/scripts/prepare-app.mjs
index 33eb835..6cf8d73 100644
--- a/packages/brand/scripts/prepare-app.mjs
+++ b/packages/brand/scripts/prepare-app.mjs
@@ -1,4 +1,4 @@
-// Run in the confirmed remote build (or an explicitly authorized dev environment).
+// Called by the consuming application's dev and build scripts.
import { copyFile, mkdir, readFile } from 'node:fs/promises';
import { resolve } from 'node:path';
const app = JSON.parse(await readFile('package.json', 'utf8'));