Files
codex-bot dba9785379
studio CI and deployment / verify-and-deploy (pull_request) Successful in 5m33s
waterfall-wiki CI and deployment / verify-and-deploy (pull_request) Successful in 16m52s
Build Studio visual layout library with recoverable design CRUD
2026-10-28 14:45:37 +08:00

150 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Studio 排版 API · 标准图文与 27 套固定构图
把本篇与图片生成文档一起交给 coding agent。agent 自行选择图片、配色、字体、构图与参数,通过 HTTP 保存渲染描述,得到可持续更新的原生 HTML/CSS 页面。数据库只保存模板关联、文字、素材引用和渲染参数,不保存截图或任意 HTML。
[打开可视化 API 库](/studio) · [读取实时 API 契约](/api/studio/designs?agent_mode=True) · [照片入皮影](/explore/3c98946754c33309d73d5284) · [街头小人](/explore/4ce3283fd98bb03a8fb39a19)
## 两类排版,同一内容模型
- **标准排版**:`standard-01`,120×160 单位。沿用原 Studio 图文页的标题、正文、栏目结构,增加主题图片与分隔线。T01 主标题、T02 正文、T03 栏目、I01 图片、D01 分隔线。所有内容和位置可设置,也能增加原生元素。
- **固定排版**:`ref-01` 至 `ref-27`,保留各自画板、出血、圆形、斜切、竖题和字体构图。先读取模板,按实际 T/I/D ID 填入内容。不能假定各模板拥有相同元素。
两类都使用 `/api/studio/designs` 的真实 CRUD。创建额外指定 layoutId;更新从 URL 确定 ID,模板关联不能修改。更换模板应创建新记录,避免把旧元素 ID 错套到新模板。用户可按需进入现有编辑工作区,工具箱功能保持可用。
## 1. 发现能力并选择模板
以下 curl 使用指定服务器。`PROMPT_TOKEN` 由用户通过现有登录方式提供,只保存在进程环境,不放 URL 或日志。也可使用已登录浏览器的同源 Cookie;浏览器写请求需要同源 Origin。未登录 API 返回 401。
```sh
BASE=http://8.211.154.134:18131
curl -fsS -H "Authorization: Bearer $PROMPT_TOKEN" "$BASE/studio/api/layouts"
curl -fsS -H "Authorization: Bearer $PROMPT_TOKEN" "$BASE/studio/api/layouts/standard-01"
curl -fsS -H "Authorization: Bearer $PROMPT_TOKEN" "$BASE/studio/api/layouts/ref-17"
```
目录返回 `version, layouts, saveApi, catalogUrl, documentationUrl`。每项包含 `id,name,family,url,api`,family 为 standard/fixed。模板返回尺寸、元素 ID/类型/role/box/direction/text、默认 parameters、workspaceSchema 与页面 URL。`?agent_mode=True` 返回纯文本文档,业务请求移除此参数。
## 2. 生成图片,上传一次,显示压缩衍生图
先让 coding agent 按生成图片文档产出文件;Studio 不暗中调用生成模型。图片可以来自用户素材或生成结果。上传走现有素材 API:
```sh
curl -fsS -H "Authorization: Bearer $PROMPT_TOKEN" \
-F kind=image -F assetOnly=true -F files=@hero.png "$BASE/api/upload"
```
返回 `assets` UUID 数组及对应 `files` 元数据。取 `assets[0]` 作为 assetId。上传不单独发帖;设计创建时才自动关联 Wiki post。不要把 Base64、任意远程 URL、HTML 或 SVG 塞入参数。
原素材保留在素材库,**页面展示只请求压缩 WebP**。以 assetId 引用素材,不必自行再上传缩略图:
```sh
curl -fsS -H "Authorization: Bearer $PROMPT_TOKEN" \
"$BASE/api/preview?source=%2Fapi%2Fmedia%2FASSET_UUID&width=960" -o hero-preview.webp
```
width 只允许 240/480/960/1280;小图预算 100KB,大图预算 220KB,复杂图片会降低尺寸/质量。原生页面按槽位显示宽度和像素密度选择 srcset 衍生图,保留 fit/cropX/cropY/zoom。目录使用原生文字与 CSS 色块,不加载参考原图;旧工具箱参考图也使用压缩预览。`/api/media/{id}` 是素材原件读取接口,不应用作展示图片的 src。
## 3. 创建:POST /api/studio/designs
创建和更新共用内容字段 `name,parameters`;`schemaVersion` 可省略,当前仅支持 1。创建额外传 `layoutId`,不传 revision 或 id。
```sh
curl -fsS -X POST "$BASE/api/studio/designs" \
-H "Authorization: Bearer $PROMPT_TOKEN" -H 'Content-Type: application/json' \
-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"}}}}'
```
有图片时在 I01 加 `assetId:"上传返回的UUID"`。固定排版只需改为所选 `layoutId`,并按 schema 选择元素 ID。例如 ref-01 支持 `texts.T01`、`texts.T02` 与 `images.I01`。
201 返回 `{design}`。design 包含:
| 字段 | 含义 |
| --- | --- |
| id / layoutId / family | 持久化 UUID、不可变模板 ID、standard 或 fixed |
| schemaVersion / revision | 参数契约版本(1)、记录修订号(从1递增) |
| name / parameters | 名称与规范化内容;省略的分组返回空对象 |
| url / renderUrl | 同一个原生 HTML/CSS 页面 URL |
| schemaUrl | 当前模板参数地址 |
| postId / postUrl | 自动创建并在后续更新中复用的 Wiki post |
| archived / archivedAt | 可恢复归档状态与时间 |
| createdAt / updatedAt | 创建与最后修改时间 |
| legacySvgUrl | 固定排版的旧 SVG 导出地址,标准排版为 null |
创建设计与 Wiki post 在同一数据库事务内完成,失败整体回滚。更新同一设计复用同一 post;手工编辑过的 Wiki 正文、标题、标签、封面不会被参数更新覆盖。
## 4. 读取与打开
```sh
ID=创建返回的UUID
curl -fsS -H "Authorization: Bearer $PROMPT_TOKEN" "$BASE/api/studio/designs/$ID"
curl -fsS -H "Authorization: Bearer $PROMPT_TOKEN" "$BASE/api/studio/designs?layoutId=standard-01&limit=20"
```
读取返回 `{design}`,没有副作用。列表默认只列未归档记录;`archived=true` 只列归档记录;limit 为1–50,默认20;`nextCursor` 作为下一页 before。layoutId 可省略。
直接打开返回的 url:`/studio/layouts/standard-01?id={UUID}` 或 `/studio/layouts/ref-17?id={UUID}`,默认看到原生页面,点击“编辑页面”才进入工作区。`/studio/designs/{UUID}` 是兼容跳转。ID 与模板不匹配返回404。归档设计仍能经 API 读取以恢复,渲染页返回404。
## 5. 更新:PATCH /api/studio/designs/{id}
先 GET,保留所有未改字段,再整体替换 parameters;不是深度合并。以下假设刚读到 revision=1:
```sh
curl -fsS -X PATCH "$BASE/api/studio/designs/$ID" \
-H "Authorization: Bearer $PROMPT_TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"观察日常 · 修订","revision":1,"parameters":{"texts":{"T01":{"value":"新的标题"}},"images":{},"decorations":{}}}'
```
200 返回新 design,revision 增加。过期 revision 返回409,重新 GET 并合并后再提交;不要盲目重试。不接受 layoutId、id、url、postId 等返回字段;不能直接把整个 design 作为 body。另存副本使用 POST 创建新 UUID。
## 6. 删除与恢复
DELETE 采用可恢复归档,不物理删除参数、素材或 Wiki post。和更新一样必须提供最新 revision;自动同步关联 post 的归档状态。
```sh
curl -fsS -X DELETE "$BASE/api/studio/designs/$ID" \
-H "Authorization: Bearer $PROMPT_TOKEN" -H 'Content-Type: application/json' -d '{"revision":2}'
# 删除后读取新 revision,再恢复。此例删除后为3:
curl -fsS -X POST "$BASE/api/studio/designs/$ID" \
-H "Authorization: Bearer $PROMPT_TOKEN" -H 'Content-Type: application/json' -d '{"revision":3,"archived":false}'
```
两者200返回 `{design}`,revision 递增。归档记录 PATCH 返回409,先恢复。重复写入仍需最新 revision;409不会修改数据。独立归档 Wiki post 只影响笔记发现状态,不等于删除设计。旧设计缺 Wiki 入口可调用 `POST /api/studio/designs/{id}/post`,body `{}`,首次201、已有200;不改变 revision。
## 参数清单(两类共用)
parameters 顶层允许 texts/images/decorations/paper/layers/added;全部可省略,不能添加未知字段。最大请求64KB。颜色都为 `#RRGGBB`。坐标与字号使用模板单位,不是 CSS 像素。
| 分组 | 字段与约束 |
| --- | --- |
| 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 |
| images.{图片ID} | assetId(已存在的图片 UUID);color;fit cover/contain;cropX/cropY 0–100(默认50);zoom 1–5(默认1) |
| decorations.{装饰ID} | color;hidden 布尔值 |
| paper | 纸张颜色 |
| 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 布尔值 |
| 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 |
新增元素先在 added 声明,然后在 texts/images/decorations/layers 用该 ID 配置。locked 控制工作区交互,不禁止 agent 更新。数据是封闭结构,无脚本执行。未来扩展新增契约版本;v1 不接受未知字段/版本。现有省略 schemaVersion 的请求继续按v1处理,旧记录无需重建,布局 ID 和页面 UUID 保持不变。默认视觉可随模板美化变化;要求固定外观时显式设置配色、字体和图层参数。
错误:400 参数/版本/构件类型/图片 ID 不合法;401 未登录;404 模板或设计不存在;409 修订冲突或已归档;405 方法不支持;413 请求超限;500 服务失败。压缩预览失败可能返回503与 Retry-After。
## 现有工具箱与兼容导出
工具功能保留:[ref-17 同一母版四张试版](/studio/ideas/learning-skills-template)、[ref-01/07/26 三种构图试版](/studio/ideas/layout-selection)、[最初图文页](/studio/ideas/first-idea)。旧封面工具文档已合并到本篇,旧文档 URL 保留为归档说明,避免重复顶级入口。
旧无状态 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。
```sh
curl -fsS -X POST "$BASE/studio/api/export/learning-skills-template?format=svg" \
-H "Authorization: Bearer $PROMPT_TOKEN" -H 'Content-Type: application/json' \
-d '{"slide":1,"heading":"笔记复习","color":"#7a8b7e"}' -o cover.svg
curl -fsS -X POST "$BASE/studio/api/export/layout-selection?format=svg" \
-H "Authorization: Bearer $PROMPT_TOKEN" -H 'Content-Type: application/json' \
-d '{"layoutId":"ref-01","fields":{"T01":"STUDY"},"color":"#83918a"}' -o selection.svg
```
固定排版 `/studio/api/layouts/ref-01` 的 GET format=svg、POST 仍提供旧分层 SVG;POST format=json 只验证和返回规范化参数。**旧 SVG 不反映 added、layers、扩展字体和裁切参数**,不能用来证明原生效果。standard-01 不支持 SVG。原生页面应直接打开返回 URL,或用浏览器打印。代码可扩展渲染能力,但每次是否使用、选择哪些参数均由 coding agent 决定。
## 固定排版索引
{{LAYOUTS}}