diff --git a/apps/wiki/public/layout-recipes/annotation-lines.html b/apps/wiki/public/layout-recipes/annotation-lines.html new file mode 100644 index 0000000..04da8b3 --- /dev/null +++ b/apps/wiki/public/layout-recipes/annotation-lines.html @@ -0,0 +1,32 @@ + + + + + +细线标注与技术图录 · 排版示例 + + + +
+ + +A / 表面结构示意 +

细节的尺度

+

标注用于解释真实细节。 +本例色块为结构占位,并非实物测量。

+
FORM / STUDIES2026 · 10
+
+ + diff --git a/apps/wiki/public/layout-recipes/annotation-lines.png b/apps/wiki/public/layout-recipes/annotation-lines.png new file mode 100644 index 0000000..ded64d8 Binary files /dev/null and b/apps/wiki/public/layout-recipes/annotation-lines.png differ diff --git a/apps/wiki/public/layout-recipes/diagonal-cards.html b/apps/wiki/public/layout-recipes/diagonal-cards.html new file mode 100644 index 0000000..0f0769f --- /dev/null +++ b/apps/wiki/public/layout-recipes/diagonal-cards.html @@ -0,0 +1,30 @@ + + + + + +轻斜卡片与拼贴 · 排版示例 + + + +
+ + +

纸上的实验

+

材料笔记 / 两张卡片的轻微偏移

+
FORM / STUDIES2026 · 09
+
+ + diff --git a/apps/wiki/public/layout-recipes/diagonal-cards.png b/apps/wiki/public/layout-recipes/diagonal-cards.png new file mode 100644 index 0000000..ed04f42 Binary files /dev/null and b/apps/wiki/public/layout-recipes/diagonal-cards.png differ diff --git a/apps/wiki/public/layout-recipes/editorial-serif.html b/apps/wiki/public/layout-recipes/editorial-serif.html new file mode 100644 index 0000000..cea6a0f --- /dev/null +++ b/apps/wiki/public/layout-recipes/editorial-serif.html @@ -0,0 +1,30 @@ + + + + + +衬线刊头与杂志栏 · 排版示例 + + + +
+

Quiet
Design

+ + +

从一块留白开始,观察材料、光线与文字之间的关系。

+
FORM / STUDIES2026 · 07
+
+ + diff --git a/apps/wiki/public/layout-recipes/editorial-serif.png b/apps/wiki/public/layout-recipes/editorial-serif.png new file mode 100644 index 0000000..d15e75f Binary files /dev/null and b/apps/wiki/public/layout-recipes/editorial-serif.png differ diff --git a/apps/wiki/public/layout-recipes/horizontal-band.html b/apps/wiki/public/layout-recipes/horizontal-band.html new file mode 100644 index 0000000..3e15861 --- /dev/null +++ b/apps/wiki/public/layout-recipes/horizontal-band.html @@ -0,0 +1,31 @@ + + + + + +横向色带与断层 · 排版示例 + + + +
+ +

留白练习

+

CHAPTER
ZERO

+

以一道横向色带, +建立章节之间的停顿。

+
FORM / STUDIES2026 · 08
+
+ + diff --git a/apps/wiki/public/layout-recipes/horizontal-band.png b/apps/wiki/public/layout-recipes/horizontal-band.png new file mode 100644 index 0000000..2836c31 Binary files /dev/null and b/apps/wiki/public/layout-recipes/horizontal-band.png differ diff --git a/apps/wiki/public/layout-recipes/modular-grid.html b/apps/wiki/public/layout-recipes/modular-grid.html new file mode 100644 index 0000000..28c2944 --- /dev/null +++ b/apps/wiki/public/layout-recipes/modular-grid.html @@ -0,0 +1,29 @@ + + + + + +模块网格与索引 · 排版示例 + + + +
+

视觉档案

+
01 / 观察
02 / 结构
03 / 材料
04 / 字体
05 / 色彩
06 / 留白
+

INDEX / SIX DESIGN STUDIES

+
FORM / STUDIES2026 · 06
+
+ + diff --git a/apps/wiki/public/layout-recipes/modular-grid.png b/apps/wiki/public/layout-recipes/modular-grid.png new file mode 100644 index 0000000..1163a89 Binary files /dev/null and b/apps/wiki/public/layout-recipes/modular-grid.png differ diff --git a/apps/wiki/public/layout-recipes/monumental-type.html b/apps/wiki/public/layout-recipes/monumental-type.html new file mode 100644 index 0000000..a586f45 --- /dev/null +++ b/apps/wiki/public/layout-recipes/monumental-type.html @@ -0,0 +1,31 @@ + + + + + +巨字与裁切 · 排版示例 + + + +
+ + +

形式与留白

+

让一个词成为画面的重心。 +DESIGN STUDIES / 2026

+
FORM / STUDIES2026 · 03
+
+ + diff --git a/apps/wiki/public/layout-recipes/monumental-type.png b/apps/wiki/public/layout-recipes/monumental-type.png new file mode 100644 index 0000000..34e9ba0 Binary files /dev/null and b/apps/wiki/public/layout-recipes/monumental-type.png differ diff --git a/apps/wiki/public/layout-recipes/offset-panels.html b/apps/wiki/public/layout-recipes/offset-panels.html new file mode 100644 index 0000000..1715db2 --- /dev/null +++ b/apps/wiki/public/layout-recipes/offset-panels.html @@ -0,0 +1,31 @@ + + + + + +错位双矩形 · 排版示例 + + + +
+ + +

秩序之间

+

以留白建立关系, +让视线缓慢移动。

+
FORM / STUDIES2026 · 01
+
+ + diff --git a/apps/wiki/public/layout-recipes/offset-panels.png b/apps/wiki/public/layout-recipes/offset-panels.png new file mode 100644 index 0000000..22a6bc5 Binary files /dev/null and b/apps/wiki/public/layout-recipes/offset-panels.png differ diff --git a/apps/wiki/public/layout-recipes/orbital-rings.html b/apps/wiki/public/layout-recipes/orbital-rings.html new file mode 100644 index 0000000..80ebaa1 --- /dev/null +++ b/apps/wiki/public/layout-recipes/orbital-rings.html @@ -0,0 +1,29 @@ + + + + + +同心圆与轨道 · 排版示例 + + + +
+ +

周而复始

+

时间的形状 / ANNUAL REVIEW / 2026

+
FORM / STUDIES2026 · 04
+
+ + diff --git a/apps/wiki/public/layout-recipes/orbital-rings.png b/apps/wiki/public/layout-recipes/orbital-rings.png new file mode 100644 index 0000000..f134191 Binary files /dev/null and b/apps/wiki/public/layout-recipes/orbital-rings.png differ diff --git a/apps/wiki/public/layout-recipes/organic-ellipse.html b/apps/wiki/public/layout-recipes/organic-ellipse.html new file mode 100644 index 0000000..4821b96 --- /dev/null +++ b/apps/wiki/public/layout-recipes/organic-ellipse.html @@ -0,0 +1,30 @@ + + + + + +有机椭圆与弧面 · 排版示例 + + + +
+ +

缓慢生长

+

一条曲线, +一处停顿。

+
FORM / STUDIES2026 · 05
+
+ + diff --git a/apps/wiki/public/layout-recipes/organic-ellipse.png b/apps/wiki/public/layout-recipes/organic-ellipse.png new file mode 100644 index 0000000..980e861 Binary files /dev/null and b/apps/wiki/public/layout-recipes/organic-ellipse.png differ diff --git a/apps/wiki/public/layout-recipes/router.png b/apps/wiki/public/layout-recipes/router.png new file mode 100644 index 0000000..3f12f9c Binary files /dev/null and b/apps/wiki/public/layout-recipes/router.png differ diff --git a/apps/wiki/public/layout-recipes/split-contrast.html b/apps/wiki/public/layout-recipes/split-contrast.html new file mode 100644 index 0000000..3e64a42 --- /dev/null +++ b/apps/wiki/public/layout-recipes/split-contrast.html @@ -0,0 +1,30 @@ + + + + + +双区对照与大留白 · 排版示例 + + + +
+ +

看见留白

+

读懂秩序

+

从空间到关系 / TWO PERSPECTIVES

+
FORM / STUDIES2026 · 11
+
+ + diff --git a/apps/wiki/public/layout-recipes/split-contrast.png b/apps/wiki/public/layout-recipes/split-contrast.png new file mode 100644 index 0000000..4a6ef13 Binary files /dev/null and b/apps/wiki/public/layout-recipes/split-contrast.png differ diff --git a/apps/wiki/public/layout-recipes/type-frame.html b/apps/wiki/public/layout-recipes/type-frame.html new file mode 100644 index 0000000..597ea35 --- /dev/null +++ b/apps/wiki/public/layout-recipes/type-frame.html @@ -0,0 +1,30 @@ + + + + + +四角字框与中心场 · 排版示例 + + + +
+

高级排版 / FORM STUDIES

+ + +

四角建立边界,中央保留呼吸。

+
FORM / STUDIES2026 · 12
+
+ + diff --git a/apps/wiki/public/layout-recipes/type-frame.png b/apps/wiki/public/layout-recipes/type-frame.png new file mode 100644 index 0000000..45ee890 Binary files /dev/null and b/apps/wiki/public/layout-recipes/type-frame.png differ diff --git a/apps/wiki/public/layout-recipes/vertical-rail.html b/apps/wiki/public/layout-recipes/vertical-rail.html new file mode 100644 index 0000000..e4126fb --- /dev/null +++ b/apps/wiki/public/layout-recipes/vertical-rail.html @@ -0,0 +1,29 @@ + + + + + +窄轨竖排 · 排版示例 + + + +
+ +

静物的秩序

+

空间研究 / 第二辑 / 2026

+
FORM / STUDIES2026 · 02
+
+ + diff --git a/apps/wiki/public/layout-recipes/vertical-rail.png b/apps/wiki/public/layout-recipes/vertical-rail.png new file mode 100644 index 0000000..f6d6221 Binary files /dev/null and b/apps/wiki/public/layout-recipes/vertical-rail.png differ diff --git a/apps/wiki/scripts/generate-layout-recipes.ts b/apps/wiki/scripts/generate-layout-recipes.ts new file mode 100644 index 0000000..685e94b --- /dev/null +++ b/apps/wiki/scripts/generate-layout-recipes.ts @@ -0,0 +1,21 @@ +/** Rebuild standalone demos and schematic covers; no browser or external assets. */ +import {mkdir,writeFile} from 'node:fs/promises'; +import path from 'node:path'; +import sharp from 'sharp'; +import {recipes,recipeHtml} from '../src/content/layouts/documents'; +async function main(){ +const target=path.resolve(import.meta.dirname,'../public/layout-recipes'); +await mkdir(target,{recursive:true}); +const esc=(s:string)=>s.replaceAll('&','&').replaceAll('<','<').replaceAll('>','>'); +const outer=(inside:string)=>`${inside}`; +for(const [i,r] of recipes.entries()){ + const graphic=outer(`${r.shapes}FORM STUDIES / ${String(i+1).padStart(2,'0')}${esc(r.name)}结构示意 · 非代码截图HTML / REACT / NEXT.JS`); + await writeFile(path.join(target,r.slug+'.html'),recipeHtml(r)+'\n'); + await sharp(Buffer.from(graphic)).png().toFile(path.join(target,r.slug+'.png')); +} +const cards=recipes.map((r,i)=>{const col=i%3,row=Math.floor(i/3);return `${r.shapes}${String(i+1).padStart(2,'0')}${esc(r.name.slice(0,4))}${esc(r.name.slice(4))}`}).join(''); +await sharp(Buffer.from(outer(`FORM STUDIES / DESIGN ROUTER高级感排版${cards}12 套构图 / 选择 → 实现 → 验收 · 结构索引`))).png().toFile(path.join(target,'router.png')); +console.log(`Generated ${recipes.length} standalone HTML demos and ${recipes.length+1} schematic PNGs.`); + +} +main().catch(error=>{console.error(error);process.exitCode=1}); diff --git a/apps/wiki/src/content/layouts/documents.ts b/apps/wiki/src/content/layouts/documents.ts new file mode 100644 index 0000000..d07b5cc --- /dev/null +++ b/apps/wiki/src/content/layouts/documents.ts @@ -0,0 +1,63 @@ +import recipes from './recipes.json'; +import type {Block} from '../skills/catalog'; +import type {GuidanceDocument,GuidanceResource} from '../skills/guidance'; +import {guidanceUrl} from '../page-links'; +export {recipes}; +export const baseCss=`*{box-sizing:border-box} +body{margin:0;background:#e4e6e1;color:#243230} +.pl-frame{width:min(100%,1080px);margin-inline:auto;container-type:inline-size} +.pl-sheet{--paper:#f5f3ec;--ink:#243230;--muted:#9aa6a5;--deep:#637574;position:relative;isolation:isolate;width:100%;aspect-ratio:3/4;overflow:hidden;background:var(--paper);color:var(--ink);font-size:1cqw;font-family:Arial,"PingFang SC","Microsoft YaHei",sans-serif} +.pl-sheet .panel{position:absolute;background:var(--muted)} +.pl-sheet .title{position:absolute;margin:0;font-weight:500;line-height:1.12;max-width:86%;overflow-wrap:anywhere} +.pl-sheet .copy{position:absolute;margin:0;font-size:2.22em;line-height:1.65;white-space:pre-line} +.pl-sheet .edition{position:absolute;left:7%;right:7%;bottom:2.5%;display:flex;justify-content:space-between;border-top:.1em solid currentColor;padding-top:.7em;font-size:1.6em;letter-spacing:.08em} + .pl-sheet.monumental-type .edition,.pl-sheet.split-contrast .edition{color:var(--paper)} +@media print{@page{size:1080px 1440px;margin:0}body{background:transparent}.pl-frame{width:1080px;max-width:none}.pl-sheet{print-color-adjust:exact;-webkit-print-color-adjust:exact}}`; +const p=(text:string):Block=>({type:'paragraph',text}); +const h=(text:string):Block=>({type:'heading',text}); +const code=(text:string):Block=>({type:'code',text}); +const links=(...refs:string[]):Block=>({type:'links',refs}); +const path=(slug:string)=>'premium-layout/'+slug; +const doc=(slug:string,title:string):GuidanceResource=>({id:slug,kind:'document',title,documentPath:path(slug),href:guidanceUrl(path(slug))+'?agent_mode=True',human:guidanceUrl(path(slug))}); +const image=(slug:string,title:string):GuidanceResource=>({id:'cover',kind:'image',title,href:'/layout-recipes/'+slug+'.png'}); +export function recipeCss(recipe:typeof recipes[number]){return baseCss+'\n'+recipe.css.replaceAll('.sheet','.pl-sheet');} +export function posterMarkup(recipe:typeof recipes[number]){return `
\n${recipe.markup}\n
FORM / STUDIES2026 · ${String(recipes.indexOf(recipe)+1).padStart(2,'0')}
\n
`;} +export function recipeHtml(recipe:typeof recipes[number]){return `\n\n\n\n\n${recipe.name} · 排版示例\n\n\n\n${posterMarkup(recipe)}\n\n`;} +export function recipeReact(recipe:typeof recipes[number]){ + const title=recipe.markup.match(/

([\s\S]*?)<\/h1>/)![1].replace(//g,' '); + const subtitle=recipe.markup.match(/

([\s\S]*?)<\/p>/)![1]; + const jsx=posterMarkup(recipe).replace(/

[\s\S]*?<\/h1>/,'

{title}

').replace(/

[\s\S]*?<\/p>/,'

{subtitle}

').replaceAll('class=','className=').replaceAll('
','
'); + return `// components/layouts/${recipe.slug}/LayoutPoster.tsx\ntype PosterProps = { title?: string; subtitle?: string };\nexport default function LayoutPoster({title = ${JSON.stringify(title)}, subtitle = ${JSON.stringify(subtitle)}}: PosterProps) {\n return (\n${jsx}\n );\n}`; +} +export function recipeNext(recipe:typeof recipes[number]){return `// app/designs/${recipe.slug}/page.tsx\nimport type { Metadata } from 'next';\nimport LayoutPoster from '@/components/layouts/${recipe.slug}/LayoutPoster';\nimport '@/components/layouts/${recipe.slug}/poster.css';\nexport const metadata: Metadata = { title: '${recipe.name} | FORM STUDIES' };\nexport default function Page() {\n return
;\n}`;} +export const layoutDocuments:GuidanceDocument[]=[{ + path:path('router'),title:'高级感排版 · 设计 Router',collection:'高级感排版', + resources:[image('router','12 套构图的结构索引'),...recipes.map((r,i)=>doc(r.slug,`${String(i+1).padStart(2,'0')} · ${r.name}`))], + blocks:[p('把“高级感”变成可执行的构图决策:先识别内容,再选择一套主构图,最后按 HTML、React 或 Next.js 环境实现。这里提供 12 套独立排版方法,风格来自用户提供的灰绿与纸白排版拼贴参考;所有示意图均为重新编排的结构图,不是原图拆分、原作者模板或代码效果截图。'), + h('输入协议'),p('收集用途(海报、封面、网页首屏或正文)、画板比例、主题标题、正文长度、主图数量、品牌色、素材来源与输出技术栈。缺省使用 1080×1440、4—8 字中文标题、40 字以内导语、纸白与灰绿。若用户给出品牌规范或尺寸,优先遵守。内容超过 90 字,先拆成多页或独立阅读正文。'), + code(JSON.stringify({task:'展览预告',canvas:{width:1080,height:1440},title:'秩序之间',body:'一段不超过 40 字的导语',images:2,tone:'克制、编辑感',stack:'next-app',output:['源码','PNG','检查记录']},null,2)), + h('选择器:先按信息结构筛选'), + p(recipes.map((r,i)=>`${String(i+1).padStart(2,'0')} / ${r.name}:${r.scene}。避免:${r.avoid}。`).join('\n')), + links(...recipes.map(r=>r.slug)), + h('调度规则与冲突优先级'),p('先满足可读性与内容完整,再满足品牌规范,最后考虑情绪。只有一张主图且短中文标题→窄轨竖排;两张主图→错位双矩形;三至六项并列→模块网格;两种观点→双区对照;文字宣言→巨字;文化导读→衬线刊头;其余按主题在圆形、弧面、色带、卡片、标注和字框之间选择。一页只选一套主构图,可借用另一套的一个小元素;不要同时叠加巨字、斜卡、圆环和多组线条。'), + code(`type Input = { items: number; images: number; verticalTitle?: boolean; comparison?: boolean; statement?: boolean; editorial?: boolean };\nexport function selectLayout(x: Input) {\n if (x.items >= 3 && x.items <= 6) return 'modular-grid';\n if (x.comparison) return 'split-contrast';\n if (x.images === 2) return 'offset-panels';\n if (x.images === 1 && x.verticalTitle) return 'vertical-rail';\n if (x.statement) return 'monumental-type';\n if (x.editorial) return 'editorial-serif';\n return 'organic-ellipse';\n}\n// 这是首轮候选选择器;items > 6 或长正文先分页,再由设计师审阅。`), + h('三条实现路线'),p('HTML:子文档中的完整 HTML 保存为 poster.html 即可运行。React:将 TSX 放在文档标明的组件目录,将同篇 CSS 代码保存为 poster.css,在应用入口 import CSS。Next.js App Router:使用同篇 TSX、CSS 和 page.tsx;保留项目已有根布局。示例中的 @/ 指向项目根目录;使用 src/ 结构时,所有路径整体移到 src/ 下,并沿用项目别名。此系列是面向 App Router 的使用文档;当前知识站本身沿用已有架构。'), + h('Next.js:新项目根布局'),code(`// app/layout.tsx;已有项目合并 lang 等必要设置,不重复嵌套 html/body。\nimport type { ReactNode } from 'react';\nexport default function RootLayout({ children }: { children: ReactNode }) {\n return {children};\n}`), + h('图片与字体'),p('所有色块都是显式结构占位,不是已加载的照片。有图片时把目标 panel div 改为 figure 并清除默认 margin;使用绝对定位的 img、width:100%、height:100%、object-fit:cover。先核对人物和产品是否被裁切;需要完整展示时改用 contain。正文 alt 描述实际图片;纯装饰使用空 alt。Next.js 使用下列 Image 写法;提供自己的本地照片,不复制参考图的品牌、二维码或未知授权素材。'), + code(`// 放在目标 panel 内;父容器保留对应布局的 absolute 与宽高,并设置 margin:0。\nimport Image from 'next/image';\n// public/hero.jpg 由你提供;sizes 表示图片显示宽度,不是原图像素。\n
\n 描述实际主体\n
\n// sizes 的 68% 仅对应双矩形主块;其他构图按自己的宽度调整。`), + p('默认示例使用系统字体,因设备不同可能换行。正式交付使用已获授权的本地中文字体和拉丁字体,限定两类字体;校验字重、缺字与标点。Next.js 可在根布局用 next/font/local 接入,路径相对该文件;只有提供了真实文件才启用。'), + code(`// 可选 app/layout.tsx;先放入 app/fonts/editorial.woff2。\nimport localFont from 'next/font/local';\nimport type { ReactNode } from 'react';\nconst editorial = localFont({src:'./fonts/editorial.woff2',display:'swap'});\nexport default function RootLayout({children}:{children:ReactNode}) {\n return {children};\n}`), + h('交互、高级工具与边界'),p('静态海报组件保持纯渲染;在 App Router 中可直接作为 Server Component。调色器、拖拽和动画控制单独放到带 use client 的小组件,通过 props 传入标题和配色。不要在服务端组件中读取 window,不把整页静态排版改为客户端渲染。需要自由曲线或严格字距时使用 SVG;需要复杂材质时再引入 Canvas/WebGL,并保留文字 DOM、静态后备图与 prefers-reduced-motion 支持。Figma 等工具可复刻同一网格与令牌;最终交付必须保留可编辑源文件。'), + h('统一令牌与代码组合'),p('每套示例独立运行;同一网页并列展示多套时,base CSS 只引入一次,各篇布局 CSS 按 slug 命名。示例中的 body 样式只适用于独立海报页,接入现有产品时移除;所有 .pl-frame / .pl-sheet 类应保留以维持容器单位。最小留白为画板宽的 7%(约 76px),底部版本行例外;正文默认 24px,说明至少 18px。深灰绿只用作形状与大字背景,小字优先深墨色与纸白。'), + h('海报缩放与网页阅读模式'),p('1080×1440 示例按整张海报等比缩放,因此手机上小字会随画板缩小,不能直接用作长文阅读页。网页交付时在海报后提供真实标题与正文,或采用下面的 reading 模式,取消绝对定位与裁切,以 16px 以上正文、自然高度重排。装饰巨字与圆环在阅读模式隐藏;视觉海报与阅读版之间避免重复朗读,可把纯展示海报整体标 aria-hidden。'), + code(`/* 可选:把 reading 类加在 pl-frame 上,用于网页内容流。 */\n.reading .pl-sheet{aspect-ratio:auto;overflow:visible;font-size:10px;padding:32px 24px}\n.reading .pl-sheet .title,.reading .pl-sheet .copy,.reading .pl-sheet .answer,.reading .pl-sheet .sub{position:static;width:auto;max-width:none;writing-mode:horizontal-tb;color:var(--ink);margin:0 0 24px}\n.reading .pl-sheet .title,.reading .pl-sheet .answer,.reading .pl-sheet .sub{font-size:32px}\n.reading .pl-sheet .copy{font-size:16px}\n.reading .pl-sheet .panel,.reading .pl-sheet .orbit,.reading .pl-sheet .oval,.reading .pl-sheet .band,.reading .pl-sheet .dark,.reading .pl-sheet .measure,.reading .pl-sheet .tag,.reading .pl-sheet .rule,.reading .pl-sheet .display,.reading .pl-sheet .corners,.reading .pl-sheet .center{display:none}\n.reading .pl-sheet .grid{position:static;display:grid;grid-template-columns:1fr;gap:16px}\n.reading .pl-sheet .cell{font-size:16px;padding:16px}\n.reading .pl-sheet .edition{position:static;font-size:12px;margin-top:32px}`), + h('执行、验收与交付协议'),p('1. 先输出 layout_id、选择理由与内容预算。2. 阅读对应子文档,生成源码并替换所有占位内容。3. 对最终页面在 1080×1440 截图,并检查 375px 与 768px:无意外横向溢出、主标题不裁切、图片主体完整。4. 验证阅读顺序、替代文本与实际文字对比;普通正文目标至少 4.5:1,大字至少 3:1。5. 若标题超出预算,先改字或减字号,再缩减装饰,不能悄悄裁掉语义文字。6. 交付源代码、使用字体与素材说明、PNG/PDF 和检查记录。'), + p('使用截图工具时等待 document.fonts.ready 与图片 decode;若使用动画,先冻结在指定帧。确认画板真实像素为 1080×1440、deviceScaleFactor=1,避免生成双倍尺寸。示意封面仅展示构图语法;生产导出必须重新渲染自己的实际源码。'), + code(JSON.stringify({layout_id:'offset-panels',reason:'两张主图,主次明确',stack:'next-app',files:['LayoutPoster.tsx','poster.css','page.tsx'],checks:{canvas:'1080x1440',title:'待验收',mobile:'待验收',contrast:'待验收'},assets:'填写字体与图片来源'},null,2)), + ], +},...recipes.map((r,i):GuidanceDocument=>({ + path:path(r.slug),title:`${String(i+1).padStart(2,'0')} · ${r.name}`,collection:'高级感排版', + resources:[image(r.slug,r.name+' · 结构示意,非代码截图'),doc('router','总览 Router · 选择、技术栈与交付协议'),{id:'demo',kind:'document',title:'打开可运行 HTML 示例',href:'/layout-recipes/'+r.slug+'.html'}], + blocks:[p(`${r.name}:${r.scene}。本篇是一套可执行的设计配方;封面是独立绘制的构图示意,实际示例以 HTML/CSS 与 React 组件为准。`),h('何时使用与停止条件'),p(`适用:${r.scene}。不适用:${r.avoid}。标题默认 4—8 个汉字、正文不超过 40 字;超出时先拆页或转阅读版。品牌色与素材可替换,保持构图关系。`),h('构图参数'),p(r.geometry),p('默认 1080×1440,3:4;纸白 #f5f3ec,灰绿 #9aa6a5,深灰绿 #637574,文字 #243230。字号按画板缩放:1em=10.8px,正文 2.22em≈24px。网页阅读模式、字体与图片替换规则由总览 Router 统一管理。'),h('制作步骤'),p(r.steps),h('HTML / CSS:完整独立文件'),p('复制以下完整代码到 poster.html;默认无需网络资源。色块为占位,替换素材时遵守 Router 的图像与版权协议。'),code(recipeHtml(r)),links('demo'),h('React / TSX:可复用组件'),p(`保存为 components/layouts/${r.slug}/LayoutPoster.tsx;支持 title 与 subtitle 字符串 props。把下段 CSS 保存为同目录 poster.css,并在 React 应用入口导入。静态组件不需要 use client。`),code(recipeReact(r)),h('React 与 Next.js 共用 CSS'),code(recipeCss(r)),h('Next.js App Router:路由接入'),p(`下面的 page.tsx 对应 /designs/${r.slug},使用上面的组件和 CSS。新项目根布局、路径别名、next/image、next/font/local 与交互边界见 Router;已有项目保留自己的根布局。`),code(recipeNext(r)),h('本构图的验收标准'),p(r.check),p('共同检查:1080×1440 下标题完整、正文与底部版本行不重叠;375px 和 768px 下等比海报无意外横向滚动。若用于网页正文,启用 Router 的阅读模式并逐项检查。所有示例只有系统字体与结构占位,替换真实标题、字体和图片后须重新验收。'),h('变体与修改顺序'),p('先替换真实内容,再调整标题字号与说明长度,随后微调图形位置;最后才改变背景色和装饰。只调整该 slug 下的布局规则,避免影响其他构图。交付保留 HTML 或 TSX/CSS 源码、素材说明与导出文件。'),links('router'), + ], +}))]; diff --git a/apps/wiki/src/content/layouts/recipes.json b/apps/wiki/src/content/layouts/recipes.json new file mode 100644 index 0000000..423f519 --- /dev/null +++ b/apps/wiki/src/content/layouts/recipes.json @@ -0,0 +1,146 @@ +[ + { + "slug": "offset-panels", + "name": "错位双矩形", + "scene": "作品集封面、摄影选集、两张主图的品牌提案", + "avoid": "三张以上同等重要的图;长篇正文", + "geometry": "主块 x=18%、y=16%、w=68%、h=37%;副块 x=37%、y=57%、w=49%、h=31%;左侧留下文字呼吸带。", + "steps": "先让两块右边缘对齐;再用不等宽与 4% 的竖向间隔制造节奏;把标题留在左上,说明压到左下。", + "check": "两块不接触;主块面积大于副块;标题与图块相距至少 24px;替换图片后两个容器比例不变。", + "css": ".sheet.offset-panels .panel-a{left:18%;top:16%;width:68%;height:37%}.sheet.offset-panels .panel-b{left:37%;top:57%;width:49%;height:31%;background:var(--deep)}.sheet.offset-panels .title{left:7%;top:6%;font-size:6em}.sheet.offset-panels .copy{left:7%;top:66%;width:25%}", + "markup": "
\n
\n

秩序之间

\n

以留白建立关系,\n让视线缓慢移动。

", + "shapes": "" + }, + { + "slug": "vertical-rail", + "name": "窄轨竖排", + "scene": "东方文化、书籍封面、展览预告;短中文标题", + "avoid": "长英文标题;必须快速扫读的大段信息", + "geometry": "主图占左侧 64%×76%,位于 x=7%、y=12%;右侧 14% 为竖排轨道;中间留 5% 通道。", + "steps": "先画主矩形;右侧建立独立竖排栏;中文使用 vertical-rl,数字日期保持横向;底部信息与主图左边对齐。", + "check": "竖排标题不超过 8 个汉字;拉丁单词不要逐字竖排;正文横排;文字不进入主图安全区。", + "css": ".sheet.vertical-rail .panel-a{left:7%;top:12%;width:64%;height:76%;background:var(--deep)}.sheet.vertical-rail .title{right:8%;top:13%;writing-mode:vertical-rl;font-size:6.3em;letter-spacing:.15em}.sheet.vertical-rail .copy{left:7%;bottom:5%;width:64%}", + "markup": "
\n

静物的秩序

\n

空间研究 / 第二辑 / 2026

", + "shapes": "" + }, + { + "slug": "monumental-type", + "name": "巨字与裁切", + "scene": "品牌宣言、创意节、单词主题封面", + "avoid": "说明密集的教程内页;不可裁切的商标", + "geometry": "中央横跨 96% 的巨字,字号 240px;底部色块高 40%;可裁切装饰英文,中文信息保持完整。", + "steps": "先写完整可读的中文主题;再将一个英文词放大并裁掉外缘 4%;让巨字压住色块边界;日期与说明保持小尺寸。", + "check": "裁切只作用于装饰字;H1 与正文不裁切;英文与主题有语义关联;字号层级至少 3:1。", + "css": ".sheet.monumental-type .panel-a{left:0;bottom:0;width:100%;height:40%;background:var(--deep)}.sheet.monumental-type .display{position:absolute;left:-4%;top:26%;font:bold 24em/.8 Georgia,serif;letter-spacing:-.08em}.sheet.monumental-type .title{left:7%;top:10%;font-size:6em}.sheet.monumental-type .copy{left:7%;bottom:10%;width:60%;color:var(--paper)}", + "markup": "
\n
FORM
\n

形式与留白

\n

让一个词成为画面的重心。\nDESIGN STUDIES / 2026

", + "shapes": "FORM" + }, + { + "slug": "orbital-rings", + "name": "同心圆与轨道", + "scene": "年度回顾、声音主题、循环或时间概念", + "avoid": "方形实物必须完整展示的产品图;严肃数据图表", + "geometry": "圆心位于画板 (50%,43%);直径 72% 画板宽;三层外环等距;下方 18% 为说明区。", + "steps": "用 aspect-ratio 保持正圆;三层细线围绕同一圆心;一处小圆作节拍;标题和说明放在圆外,避免环形正文。", + "check": "窄屏仍为正圆;环线不穿过文字;不要把装饰环误称数据刻度;有动画时尊重减少动态偏好。", + "css": ".sheet.orbital-rings .orbit{position:absolute;left:14%;top:16%;width:72%;aspect-ratio:1;border-radius:50%;background:var(--deep);box-shadow:0 0 0 1.2em var(--paper),0 0 0 1.3em var(--muted),0 0 0 2.5em var(--paper),0 0 0 2.6em var(--muted),0 0 0 3.8em var(--paper),0 0 0 3.9em var(--muted)}.sheet.orbital-rings .title{left:7%;bottom:15%;font-size:6.5em}.sheet.orbital-rings .copy{left:7%;bottom:6%;width:80%}", + "markup": "
\n

周而复始

\n

时间的形状 / ANNUAL REVIEW / 2026

", + "shapes": "" + }, + { + "slug": "organic-ellipse", + "name": "有机椭圆与弧面", + "scene": "生活方式、艺术展、柔和的品牌视觉", + "avoid": "精准工程数据;需要硬边产品轮廓的主视觉", + "geometry": "宽 102%、高 62% 的椭圆自右侧出血;中心落在右半区;左上与左下各保留一块完整文字区。", + "steps": "先建立椭圆,旋转 -12 度;只裁掉形状外缘;标题放左上,说明放左下;不要再叠加第二个大形状。", + "check": "椭圆与标题无交叠;出血边缘不生成横向滚动;曲线的视觉重量在右侧;正文底部安全距至少 64px。", + "css": ".sheet.organic-ellipse .oval{position:absolute;left:24%;top:27%;width:102%;height:62%;border-radius:50%;transform:rotate(-12deg);background:var(--deep)}.sheet.organic-ellipse .title{left:7%;top:10%;font-size:6.5em}.sheet.organic-ellipse .copy{left:7%;bottom:7%;width:40%}", + "markup": "
\n

缓慢生长

\n

一条曲线,\n一处停顿。

", + "shapes": "" + }, + { + "slug": "modular-grid", + "name": "模块网格与索引", + "scene": "作品目录、系列课程、设计档案;3—6 个平级项目", + "avoid": "只有一张图的情绪封面;长故事", + "geometry": "12 栏思维;主体为两列三行,列间距 3%、行间距 2%;左上预留标题与索引。", + "steps": "先确定信息项数量;使用等宽网格;每格保留编号与短标题;只用一个深色格建立主次,其余保持同一色阶。", + "check": "顺序与 DOM 阅读顺序一致;每项标题不超过 8 字;格间距一致;内容超出六项时分页,不能挤小文字。", + "css": ".sheet.modular-grid .grid{position:absolute;left:7%;right:7%;top:28%;bottom:13%;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2em}.sheet.modular-grid .cell{padding:2em;background:var(--muted);font-size:2.6em}.sheet.modular-grid .cell:first-child{background:var(--deep);color:var(--paper)}.sheet.modular-grid .title{left:7%;top:10%;font-size:6.5em}.sheet.modular-grid .copy{left:7%;bottom:5%;width:86%}", + "markup": "

视觉档案

\n
01 / 观察
02 / 结构
03 / 材料
04 / 字体
05 / 色彩
06 / 留白
\n

INDEX / SIX DESIGN STUDIES

", + "shapes": "" + }, + { + "slug": "editorial-serif", + "name": "衬线刊头与杂志栏", + "scene": "文化杂志、建筑专题、品牌故事导读", + "avoid": "紧急公告;复杂交互控制台", + "geometry": "顶部刊头高 18%;中央图块占 58%×49%;右侧 25% 为短导语;底部期号区与分隔线对齐。", + "steps": "用衬线字建立刊头;用无衬线字写导语;主图与旁栏共用顶部基线;正文超过 90 个汉字就另起阅读页。", + "check": "全页最多两类字体;标题不超过两行;导语每行约 10—14 字;细线只分区,不包围所有段落。", + "css": ".sheet.editorial-serif .title{left:7%;top:7%;font:7.8em/.95 Georgia,\"Songti SC\",serif}.sheet.editorial-serif .panel-a{left:7%;top:32%;width:58%;height:49%}.sheet.editorial-serif .copy{left:70%;top:33%;width:23%;font-size:2em;line-height:1.8}.sheet.editorial-serif .rule{position:absolute;left:7%;right:7%;top:27%;border-top:.15em solid var(--ink)}", + "markup": "

Quiet
Design

\n
\n
\n

从一块留白开始,观察材料、光线与文字之间的关系。

", + "shapes": "" + }, + { + "slug": "horizontal-band", + "name": "横向色带与断层", + "scene": "章节扉页、品牌手册、主题分组页", + "avoid": "三段以上相互独立的内容;密集菜单", + "geometry": "中央色带贯穿 100% 宽,位于 y=34%—67%;标题跨上边界,说明置于底部左侧。", + "steps": "先画全宽色带;把一个短主题放在色带上方;用浅底与深带产生节奏;底部元信息保持同一左边界。", + "check": "标题不能被色带边界切成难读的两段;带内文字保持足够对比;色带只负责分区,不伪装成按钮。", + "css": ".sheet.horizontal-band .band{position:absolute;left:0;top:34%;width:100%;height:33%;background:var(--deep)}.sheet.horizontal-band .title{left:7%;top:12%;font-size:7em}.sheet.horizontal-band .sub{position:absolute;left:7%;top:43%;font-size:5.5em;color:var(--paper);line-height:1.1}.sheet.horizontal-band .copy{left:7%;bottom:12%;width:65%}", + "markup": "
\n

留白练习

\n

CHAPTER
ZERO

\n

以一道横向色带,\n建立章节之间的停顿。

", + "shapes": "CHAPTER ZERO" + }, + { + "slug": "diagonal-cards", + "name": "轻斜卡片与拼贴", + "scene": "创意工作室、实验记录、艺术项目封面", + "avoid": "正式表格;大量小字;多张同时倾斜的图", + "geometry": "后卡片旋转 -5 度,前卡片旋转 3 度;两张卡错开 6%;组合限制在 x=14%—86%、y=24%—78%。", + "steps": "先构造两张同尺寸卡片;只给前后卡片相反的小角度;固定重叠顺序;标题和说明始终水平。", + "check": "倾斜不超过 6 度;角点留在安全区;不要给正文整体旋转;阴影只用一层低透明度。", + "css": ".sheet.diagonal-cards .back{left:14%;top:27%;width:66%;height:49%;transform:rotate(-5deg);background:#dce0da}.sheet.diagonal-cards .front{left:20%;top:29%;width:66%;height:49%;transform:rotate(3deg);background:var(--deep);box-shadow:0 .6em 1.2em #24323015}.sheet.diagonal-cards .title{left:7%;top:8%;font-size:6.5em}.sheet.diagonal-cards .copy{left:7%;bottom:8%;width:80%}", + "markup": "
\n
\n

纸上的实验

\n

材料笔记 / 两张卡片的轻微偏移

", + "shapes": "" + }, + { + "slug": "annotation-lines", + "name": "细线标注与技术图录", + "scene": "产品细节、工艺流程、设计参数的导读页", + "avoid": "真实数值图表;没有可解释对象的纯装饰", + "geometry": "中心图块位于 x=20%、y=24%,宽 60%、高 48%;两侧各有一条标注线;上方标题、下方解释。", + "steps": "确定真正要说明的两个部位;用 1—2px 线连接短标注;线条不得穿过文字;尺寸和参数必须由真实资料提供。", + "check": "线条最多三条;每条标注有对应对象;示意数字注明非测量值;线宽导出后仍清晰。", + "css": ".sheet.annotation-lines .panel-a{left:20%;top:24%;width:60%;height:48%}.sheet.annotation-lines .measure{position:absolute;left:8%;top:35%;width:84%;height:24%;border-top:.15em solid var(--ink);border-bottom:.15em solid var(--ink)}.sheet.annotation-lines .tag{position:absolute;left:8%;top:31%;font-size:1.8em;background:var(--paper);padding:.2em}.sheet.annotation-lines .title{left:7%;top:9%;font-size:6.5em}.sheet.annotation-lines .copy{left:7%;bottom:10%;width:75%}", + "markup": "
\n
\nA / 表面结构示意\n

细节的尺度

\n

标注用于解释真实细节。\n本例色块为结构占位,并非实物测量。

", + "shapes": "" + }, + { + "slug": "split-contrast", + "name": "双区对照与大留白", + "scene": "新旧对照、两种材质、设计观点对谈", + "avoid": "需要精密等量比较的统计图;超过两种方案", + "geometry": "上区 48% 高保留纸白;下区 52% 为深灰绿;两个信息块以相同左边界连接。", + "steps": "先确认两个区块是对照还是递进;上下各保留一处标题;深区使用浅字;用相同编号系统说明关系。", + "check": "两个区域的关系能一句话说清;深区小字对比足够;边界没有压住文字;阅读顺序先上后下。", + "css": ".sheet.split-contrast .dark{position:absolute;left:0;top:48%;width:100%;height:52%;background:var(--deep)}.sheet.split-contrast .title{left:7%;top:12%;font-size:7.5em}.sheet.split-contrast .answer{position:absolute;left:7%;top:59%;font-size:7.5em;line-height:1.1;color:var(--paper);margin:0}.sheet.split-contrast .copy{left:7%;bottom:10%;width:80%;color:var(--paper)}", + "markup": "
\n

看见留白

\n

读懂秩序

\n

从空间到关系 / TWO PERSPECTIVES

", + "shapes": "读懂秩序" + }, + { + "slug": "type-frame", + "name": "四角字框与中心场", + "scene": "设计展、海报合集、极短主题的概念封面", + "avoid": "完整句子必须连续阅读的文案;长标题", + "geometry": "四个角字构成外框,中心 58%×52% 为主形;阅读用完整 H1,分散角字仅作为装饰副本。", + "steps": "选择四字主题;先提供完整语义标题;再把四个装饰字分布四角;中央只留一个图形,说明放底部。", + "check": "屏幕阅读器只读一次完整标题;四角不被裁切;中央图形不压字;四角间距视觉平衡。", + "css": ".sheet.type-frame .title{left:7%;top:7%;font-size:3em}.sheet.type-frame .center{position:absolute;left:21%;top:25%;width:58%;height:52%;border-radius:50%;background:var(--muted)}.sheet.type-frame .corners{position:absolute;inset:15% 7% 17%;display:grid;grid-template-columns:1fr 1fr;align-content:space-between;font:10em/1 \"Songti SC\",serif}.sheet.type-frame .corners span:nth-child(even){text-align:right}.sheet.type-frame .copy{left:7%;bottom:6%;width:86%}", + "markup": "

高级排版 / FORM STUDIES

\n
\n
高级排版
\n

四角建立边界,中央保留呼吸。

", + "shapes": "高级排版" + } +] diff --git a/apps/wiki/src/content/page-ids.json b/apps/wiki/src/content/page-ids.json index 781b809..b7b0112 100644 --- a/apps/wiki/src/content/page-ids.json +++ b/apps/wiki/src/content/page-ids.json @@ -12,5 +12,18 @@ "wiki:Main:welcome": "54d12ae51429f66fa7991ef5", "wiki:Help:namespaces": "1a33340838520492b2e095c0", "wiki:Template:idea": "40e0e456e2f5943610fef538", - "wiki:Draft:inbox": "a599a5734d13ec81fed1ffd1" + "wiki:Draft:inbox": "a599a5734d13ec81fed1ffd1", + "guidance:premium-layout/router": "8eb8c76500580f7a4b56ba3c", + "guidance:premium-layout/offset-panels": "5971fc3d2563aa8005df5c13", + "guidance:premium-layout/vertical-rail": "9ad47529a7eaeee1fef771ca", + "guidance:premium-layout/monumental-type": "7f158059ba3a2b80dd750cc3", + "guidance:premium-layout/orbital-rings": "370d1881f229af63f1946df9", + "guidance:premium-layout/organic-ellipse": "31a978620a0d388f84772c95", + "guidance:premium-layout/modular-grid": "c34cf81137654ad38850c9bd", + "guidance:premium-layout/editorial-serif": "dbe94ccaa708bd120549ae86", + "guidance:premium-layout/horizontal-band": "768587e537d6f1ee77a51961", + "guidance:premium-layout/diagonal-cards": "0962c2bf1c558e0e32425f59", + "guidance:premium-layout/annotation-lines": "347b732caa4af4afa43b65a4", + "guidance:premium-layout/split-contrast": "3edf144a443c1fdf23827fb3", + "guidance:premium-layout/type-frame": "97227671a9dc95c4948e591b" } diff --git a/apps/wiki/src/content/skills/guidance.ts b/apps/wiki/src/content/skills/guidance.ts index ed8c258..59d7cb2 100644 --- a/apps/wiki/src/content/skills/guidance.ts +++ b/apps/wiki/src/content/skills/guidance.ts @@ -1,4 +1,5 @@ import {guidanceUrl} from '../page-links'; +import {layoutDocuments} from '../layouts/documents'; import {getSkill,skillCatalog,type Block,type Resource} from './catalog'; export type GuidanceResource=Resource&{documentPath?:string}; @@ -43,6 +44,7 @@ guidanceDocuments.push({ {type:'links',refs:['doc:street-people/checks','doc:shadow-puppet/delivery']}, ], }); +guidanceDocuments.unshift(...layoutDocuments); const registry=new Map(guidanceDocuments.map(doc=>[doc.path,doc])); export function getGuidance(path:string){return registry.get(path);} export function guidanceBacklinks(path:string){return guidanceDocuments.filter(doc=>doc.path!==path&&doc.blocks.some(b=>b.type==='links'&&b.refs!.some(id=>doc.resources.find(r=>r.id===id)?.documentPath===path)));} diff --git a/docs/premium-layouts.md b/docs/premium-layouts.md new file mode 100644 index 0000000..708299d --- /dev/null +++ b/docs/premium-layouts.md @@ -0,0 +1,40 @@ +# 高级感排版文档组 + +新增 13 篇指导 post:一篇设计 Router 与 12 篇构图配方。通过已有指导文档注册表进入首页、分类与独立详情;每篇共用相同 ID 的网页和 `?agent_mode=True` 纯文本,不另外复制数据库 post。 + +## 文件与目的 + +- `apps/wiki/src/content/layouts/recipes.json`:12 套构图的适用条件、几何参数、步骤、独立 CSS/HTML、验收条件及封面结构图形。 +- `apps/wiki/src/content/layouts/documents.ts`:Router、输入/输出协议、调度选择器、字体与图片策略、阅读模式、公共 CSS,以及逐篇生成完整 HTML、支持属性的 React TSX 与 Next.js App Router 接入代码。 +- `apps/wiki/src/content/skills/guidance.ts`:将 13 篇内容接入既有全局文档注册表,并排在首页前部;沿用分类、正文与反向引用机制。 +- `apps/wiki/src/content/page-ids.json`:为 13 篇文档持久保存独立 ID,标题与排序变化不改变地址。 +- `apps/wiki/scripts/generate-layout-recipes.ts`:重新生成独立 HTML 演示和 PNG 结构封面,无第三方素材和浏览器依赖。 +- `apps/wiki/public/layout-recipes/router.png`:12 套构图的总览封面。 +- `docs/premium-layouts.md`:内容入口、文件职责、重建与验证说明(本文)。 + +以下每个文件基名各对应 `.html` 与 `.png` 两个文件,全部位于 `apps/wiki/public/layout-recipes/`。HTML 为实际可运行示例;PNG 是独立绘制的结构示意,明确标注并非代码截图。 + +| 文件基名 | 构图与目的 | +| --- | --- | +| `offset-panels` | 错位双矩形:两张主图的主次与边缘对齐 | +| `vertical-rail` | 窄轨竖排:短中文标题与主图并列 | +| `monumental-type` | 巨字与裁切:通过装饰英文建立宣言重心 | +| `orbital-rings` | 同心圆与轨道:表达周期与时间 | +| `organic-ellipse` | 有机椭圆与弧面:柔和品牌的出血曲线 | +| `modular-grid` | 模块网格与索引:六项内容的秩序 | +| `editorial-serif` | 衬线刊头与杂志栏:文化导读的刊头与边栏 | +| `horizontal-band` | 横向色带与断层:章节之间的视觉停顿 | +| `diagonal-cards` | 轻斜卡片与拼贴:实验记录的纸张层次 | +| `annotation-lines` | 细线标注与技术图录:对象与短标注的对应关系 | +| `split-contrast` | 双区对照与大留白:上下两种观点的对照 | +| `type-frame` | 四角字框与中心场:语义标题与装饰副本分离 | + +## 重建与验证 + +从 `apps/wiki` 目录执行 `node --import tsx scripts/generate-layout-recipes.ts`。既有文档与 explore 测试覆盖所有新增 ID、全局引用、Markdown 与资源计数。使用 tsc 检查内容生成器;用 esbuild 逐篇编译文档中的 React、Next.js 与 CSS,并通过 React 服务端渲染验证标题与说明属性。 + +只在生产服务器验收页面,不启动本地网页预览。推送后等待 ces-control CI 完成生产构建和集成检查,再检查实际首页、排版分类、Router、子文档、纯文本和独立 HTML。 + +## 边界 + +这是一组可复用的设计教学文档,不是将参考图逐格临摹成商业模板。示例使用系统字体与占位色块;真实标题、字体、照片和移动端阅读模式必须按最终内容重新检查。文档中的 Next.js 示例面向 App Router,不改变本站已有路由架构。