diff --git a/content/studio-tools/tutorial.md b/content/studio-tools/tutorial.md
new file mode 100644
index 0000000..b30f085
--- /dev/null
+++ b/content/studio-tools/tutorial.md
@@ -0,0 +1,129 @@
+这篇 post 是两件 Studio 封面工具的使用入口与 API 教程。工具负责可编辑预览和渲染;waterfall-wiki 保存说明、图片、来源链接与调用示例。当前只做模板与主题占位,不填入具体 Skills 合集。
+
+## 打开工具
+
+- [同一母版/四张试版](/studio/ideas/learning-skills-template):一张空白母版,加笔记复习、教学资料、英语学习三张占位封面。四张共用 ref-17 九个构件的坐标;可统一改英文刊头,分别改中文标题、简介和配色。
+- [三种构图/模板选择工具](/studio/ideas/layout-selection):切换 ref-01、ref-07、ref-26,每种构图独立编辑文字、主图色、副图色。切换模板保留当前页内各模板的修改;刷新恢复初始值。
+
+Studio 没有独立目录首页;访问 /studio 会回到 waterfall-wiki。请从本文的具体工具链接进入。页面上的下载可以保存 SVG、参数 JSON;工具不自动把试版发布为 Wiki post。
+
+## 先看图,再选模板
+
+{{GALLERY}}
+
+## 构件对应与来源
+
+| 工具 | 模板 | 构图 | 构件数 |
+| --- | --- | --- | --- |
+| 同一母版四张试版 | [ref-17](/explore/7b1b2fc5b9690213bbbe07ac) | 两行英文刊头、圆形叠标、左下主图、右侧窄栏 | 9 |
+| 三种构图 | [ref-01](/explore/eb937b42be92a9f6feee684f) | 双矩形错位、品牌字标、左下说明 | 6 |
+| 三种构图 | [ref-07](/explore/7d4cefdfada28bbe9e570af3) | 同心圆主图、环形文字、底部年份与说明 | 7 |
+| 三种构图 | {{REF26}} | 三行英文、右侧竖排标题、曲线与小图 | 11 |
+
+完整来源:[27 张原图 Router](/explore/8eb8c76500580f7a4b56ba3c)。各原图 post 内有文本、图片、原画板与 T/I/D 坐标,阅读纯文本可加 ?agent_mode=True。构件必须带上完整键,例如 ref-01/T01;不同模板不能混用同名构件。
+
+T 是可编辑文字,I 是图片位或色块,D 是装饰。ref-01 的品牌字标只有一个 T01,左下说明为 T02,没有重复 T03。工具保持每张原图的画板比例。ref-17 为重新绘制的文字、色块与线条;另外三种模板的图位保留原始形状蒙版,装饰沿用从原图分离的 PNG 图层,文字重新排版。它们是来源约束下的试版,替换内容后的字形与色调不会与原图逐像素相同。低分辨率原图的装饰放大仍可能有像素感。
+
+## API:读取模板与原始试版
+
+接口统一使用 waterfall-wiki 的同一域名。所有接口说明先读:
+
+- [Studio API 目录](/studio/api)
+- [封面工具 API 纯文本说明](/studio/api/export/learning-skills-template?agent_mode=True)
+
+```bash
+BASE='http://8.211.154.134:18131'
+# version:2,四张试版、共享模板、原始几何和来源链接
+curl "$BASE/studio/api/export/learning-skills-template"
+# 第 2 张初始封面,slide 从 0 开始
+curl "$BASE/studio/api/export/learning-skills-template?format=svg&slide=1" -o notes.svg
+# version:3,三种模板的 slots、fields、内嵌图位蒙版与装饰
+curl "$BASE/studio/api/export/layout-selection"
+# 指定原图模板
+curl "$BASE/studio/api/export/layout-selection?format=svg&layoutId=ref-07" -o circle.svg
+```
+
+GET 省略 format 返回 JSON;format=markdown 返回文本资料;format=svg 返回初始封面。JSON 是 AI 可读取的几何与文字数据,SVG 是可独立打开的图像。
+
+## API:提交自己的参数生成 SVG
+
+POST 是无状态渲染,不修改 Wiki 或工具初始数据。Content-Type 为 application/json;format=svg 为默认值,format=json 返回经过校验的参数与模板。请求最大 32KB,返回的正式 SVG 不带构件辅助线。
+
+```bash
+curl -X POST "$BASE/studio/api/export/learning-skills-template?format=svg" \
+ -H 'Content-Type: application/json' \
+ --data '{"slide":1,"heading":"笔记复习","body":"课程 · 笔记\n复习主题占位\n正文稍后填入","color":"#7a8b7e","accent":"#d5ddcf","masthead":["STUDY","Skills"]}' \
+ -o notes-custom.svg
+
+curl -X POST "$BASE/studio/api/export/layout-selection?format=svg" \
+ -H 'Content-Type: application/json' \
+ --data '{"layoutId":"ref-01","fields":{"T01":"STUDY","T02":"笔记复习\n主题说明占位\n正文稍后填入"},"color":"#83918a","accent":"#c3cec5"}' \
+ -o ref-01-custom.svg
+```
+
+四张试版参数:slide 为 0–3 的整数;heading 为 1–6 字;body 最多 360 字、3 行;masthead 为两行英文,每行 1–8 个英文字母或空格。多模板参数:layoutId 必填;fields 只能使用目标模板真实存在的 T 编号,每项 1–120 字、最多 4 行;未提供的字段保留默认值。颜色必须是 #RRGGBB。未知模板、构件 ID、参数、超长文字或无效颜色返回 400;不存在的工具返回 404;不支持的方法返回 405;请求过大返回 413。
+
+## HTML / CSS 使用
+
+只需展示初始封面时,直接把 SVG 接口作为图像,无需部署新页面或复制图层:
+
+```html
+
+
+
+
+```
+
+## React 使用
+
+```tsx
+export function TemplateCover({ slide = 1 }: { slide?: number }) {
+ return
;
+}
+```
+
+自定义渲染:通过你的服务端调用 POST,保存返回的 SVG 或将其作为图像响应交给浏览器。接口没有开放任意跨站 JavaScript 的 CORS;跨域浏览器可以用 img 展示 GET 图片,POST 则从你自己的后端调用。
+
+## Next.js 使用
+
+```ts
+// app/api/cover/route.ts:为自己应用生成 SVG,不把远端 SVG 插入 innerHTML。
+export async function GET() {
+ const upstream = await fetch(
+ 'http://8.211.154.134:18131/studio/api/export/layout-selection?format=svg',
+ {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ layoutId: 'ref-26',
+ fields: { T01: 'Study 01', T02: 'Learn', T03: 'Create', T04: '学习合集' },
+ color: '#7c8e9b'
+ }),
+ cache: 'no-store'
+ }
+ );
+ if (!upstream.ok) return new Response('封面生成失败', { status: 502 });
+ return new Response(await upstream.arrayBuffer(), {
+ headers: { 'Content-Type': 'image/svg+xml; charset=utf-8' }
+ });
+}
+// 页面中使用
。
+```
+
+如果自己的站点使用 HTTPS,应通过同源后端代理此 HTTP 服务,避免浏览器混合内容限制。
+
+## 试版验收
+
+1. 四张同母版封面的 ref-17 构件数、坐标、图层次序完全相同;只替换文字与颜色。
+2. 多模板工具的 ref-01、ref-07、ref-26 分别有 6、7、11 个构件,不能偷换构图。
+3. T 文本可编辑,I 图片位是占位色块,D 装饰不冒充文字;原图未辨识的微字不猜写为“原文”。
+4. 浏览器预览与 API 使用同一渲染组件。修改后不溢出;环形、竖排、两矩形错位保持原位置。
+5. SVG 独立打开无缺图;API 不需要先访问 Studio 首页;教程可作为普通 Wiki post 的纯文本读取。
+6. 本阶段只有模板和主题占位,没有自动生成或发布三篇具体 Skills 合集。
diff --git a/scripts/publish-studio-tools.mjs b/scripts/publish-studio-tools.mjs
new file mode 100644
index 0000000..cf618ff
--- /dev/null
+++ b/scripts/publish-studio-tools.mjs
@@ -0,0 +1,18 @@
+/** Publish a normal Wiki tutorial using only generic post, tag and media APIs. */
+import {readFile,writeFile,mkdir} from 'node:fs/promises';
+const base=(process.env.WIKI_BASE||'http://8.211.154.134:18131').replace(/\/$/,''),out='output/studio-tools',publicId='9ebd8f78d54b4b9db741b4e8';
+await mkdir(out,{recursive:true});
+async function api(path,options={}){const r=await fetch(base+path,{...options,signal:AbortSignal.timeout(60000)});if(r.status===404)return null;if(!r.ok)throw Error(path+': '+r.status+' '+(await r.text()).slice(0,300));return r.json()}
+const post=(path,body,method='POST')=>api(path,{method,headers:{'Content-Type':'application/json'},body:JSON.stringify(body)});
+let state;try{state=JSON.parse(await readFile(out+'/published.json','utf8'))}catch{state={base,assets:{}}}if(state.base!==base)throw Error('Wrong publish target');
+for(const name of ['cover.png','ref17-master.png','ref17-notes.png','ref17-teaching.png','ref17-english.png','ref-01.png','ref-07.png','ref-26.png']){
+ if(state.assets[name])continue;const form=new FormData();form.set('kind','image');form.set('assetOnly','true');form.append('files',new Blob([await readFile(out+'/'+name)],{type:'image/png'}),name);
+ const data=await api('/api/upload',{method:'POST',body:form});state.assets[name]=data.assets[0];await writeFile(out+'/published.json',JSON.stringify(state,null,2));
+}
+const ids=JSON.parse(await readFile('content/layout-reference/post-ids.json','utf8'));
+const gallery=Object.entries(state.assets).filter(([name])=>name!=='cover.png').map(([name,id])=>``).join('\n\n');
+const text=(await readFile('content/studio-tools/tutorial.md','utf8')).replace('{{GALLERY}}',gallery).replace('{{REF26}}',`[ref-26](/explore/${ids['ref-26']})`);
+const tag=await post('/api/tags',{name:'Studio工具',slug:'studio-tools'}),title='Studio 封面工具 · 同一母版与三种构图',description='从 waterfall-wiki 进入两件 Studio 工具:ref-17 四张同母版试版,以及 ref-01/07/26 三种构图。含可访问图像、GET/POST API、HTML/React/Next.js 示例与构件验收。';
+const assets=Object.values(state.assets).map(id=>({id,role:'content'})),coverAssetId=state.assets['cover.png'],old=await api('/api/notes/'+publicId);
+state.post=old?await post('/api/notes/'+publicId,{title,description,markdown:text,tags:[tag.id],assets,coverAssetId,revision:old.entry.revision},'PUT'):await post('/api/posts',{publicId,slug:'studio-cover-tools',kind:'article',title,description,text,tags:[tag.id],assets,coverAssetId});
+await writeFile(out+'/published.json',JSON.stringify(state,null,2));console.log(base+'/explore/'+publicId);