mirror of
https://github.com/aculix/huashu-design.git
synced 2026-10-27 07:15:54 +00:00
init: huashu-design skill v1.0
花叔设计工作台 —— AI 驱动的 HTML 设计工作流,支持 Claude Code / Codex / Cursor / Trae / OpenClaw / Hermes Agent 等任意 skill-compatible agent。 四条主干能力: - HTML 高保真视觉产出(原型/App/幻灯片/动画/变体/信息图) - 设计方向顾问 Fallback(5 流派 × 20 设计哲学 × 24 预制 showcase) - Junior Designer 工作流(先 show 假设再迭代) - 专家级 5 维度评审(哲学/层级/执行/功能/创新) 工程工具链: - HTML → 25fps/60fps MP4 + palette GIF,含 6 首场景化 BGM - HTML → PDF / PPTX 导出 - Playwright 截图 + 控制台错误验证 - iOS/Android/macOS/Browser 设备边框 + Stage/Sprite 动画引擎 初版包含 SKILL.md + 13 份 references + 7 个 scripts + 18 类 assets。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
7d7bab4a82
89 files changed
+19270
No files matched your search
@@ -0,0 +1,245 @@
|
||||
# Animation Pitfalls:HTML 动画踩过的坑与规则
|
||||
|
||||
做动画时最常踩的 bug 和如何避免。每条规则都来自真实失败案例。
|
||||
|
||||
写动画之前读完这篇,能省一轮迭代。
|
||||
|
||||
## 1. 叠层布局 —— `position: relative` 是默认义务
|
||||
|
||||
**踩的坑**:一个 sentence-wrap 元素包了 3 个 bracket-layer(`position: absolute`)。没给 sentence-wrap 设 `position: relative`,结果 absolute 的 bracket 以 `.canvas` 为坐标系,飘到屏幕底部 200px 外。
|
||||
|
||||
**规则**:
|
||||
- 任何包含 `position: absolute` 子元素的容器,**必须**显式 `position: relative`
|
||||
- 即使视觉上不需要「偏移」,也要写 `position: relative` 作为坐标系锚点
|
||||
- 如果你在写 `.parent { ... }`,其子元素里有 `.child { position: absolute }`,下意识给 parent 加 relative
|
||||
|
||||
**快速检查**:每出现一个 `position: absolute`,往上数 ancestor,确保最近的 positioned 祖先是你*想要的*坐标系。
|
||||
|
||||
## 2. 字符陷阱 —— 不依赖稀有 Unicode
|
||||
|
||||
**踩的坑**:想用 `␣` (U+2423 OPEN BOX) 可视化「空格 token」。Noto Serif SC / Cormorant Garamond 都没这个字形,渲染为空白/豆腐,观众完全看不到。
|
||||
|
||||
**规则**:
|
||||
- **动画里出现的每个字符,都必须在你选定的字体里存在**
|
||||
- 常见稀有字符黑名单:`␣ ␀ ␐ ␋ ↩ ⏎ ⌘ ⌥ ⌃ ⇧ ␦ ␖ ␛`
|
||||
- 要表达「空格 / 回车 / 制表符」这类元字符,用 **CSS 构造的语义盒子**:
|
||||
```html
|
||||
<span class="space-key">Space</span>
|
||||
```
|
||||
```css
|
||||
.space-key {
|
||||
display: inline-flex;
|
||||
padding: 4px 14px;
|
||||
border: 1.5px solid var(--accent);
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
font-size: 0.3em;
|
||||
letter-spacing: 0.2em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
```
|
||||
- Emoji 也要验证:某些 emoji 在 Noto Emoji 以外字体会 fallback 成灰色方框,最好用 `emoji` font-family 或 SVG
|
||||
|
||||
## 3. 数据驱动的 Grid/Flex 模板
|
||||
|
||||
**踩的坑**:代码里 `const N = 6` 个 tokens,但 CSS 写死 `grid-template-columns: 80px repeat(5, 1fr)`。结果第 6 个 token 没有 column,整个矩阵错位。
|
||||
|
||||
**规则**:
|
||||
- 当 count 从 JS 数组来(`TOKENS.length`),CSS 模板也应该数据驱动
|
||||
- 方案 A:用 CSS 变量从 JS 注入
|
||||
```js
|
||||
el.style.setProperty('--cols', N);
|
||||
```
|
||||
```css
|
||||
.grid { grid-template-columns: 80px repeat(var(--cols), 1fr); }
|
||||
```
|
||||
- 方案 B:用 `grid-auto-flow: column` 让浏览器自动扩展
|
||||
- **禁用「固定数字 + JS 常量」的组合**,N 改了 CSS 不会同步更新
|
||||
|
||||
## 4. 过渡断层 —— 场景切换要连续
|
||||
|
||||
**踩的坑**:zoom1 (13-19s) → zoom2 (19.2-23s) 之间,主句子已经 hidden,zoom1 fade out(0.6s)+ zoom2 fade in(0.6s)+ stagger delay(0.2s+)= 约 1 秒纯空白画面。观众以为动画卡住了。
|
||||
|
||||
**规则**:
|
||||
- 连续切换场景时,fade out 和 fade in 要**交叉重叠**,不是前一个完全消失再开始下一个
|
||||
```js
|
||||
// 差:
|
||||
if (t >= 19) hideZoom('zoom1'); // 19.0s out
|
||||
if (t >= 19.4) showZoom('zoom2'); // 19.4s in → 中间 0.4s 空白
|
||||
|
||||
// 好:
|
||||
if (t >= 18.6) hideZoom('zoom1'); // 提前 0.4s 开始 fade out
|
||||
if (t >= 18.6) showZoom('zoom2'); // 同时 fade in(cross-fade)
|
||||
```
|
||||
- 或者用一个「锚点元素」(如主句子)作为场景之间的视觉连接,zoom 切换期间它短暂回显
|
||||
- 配 CSS transition 的 duration 算清楚,避免 transition 还没结束就触发下一个
|
||||
|
||||
## 5. Pure Render 原则 —— 动画状态应可 seek
|
||||
|
||||
**踩的坑**:用 `setTimeout` + `fireOnce(key, fn)` 链式触发动画状态。正常播放没问题,但做逐帧录制/seek到任意时间点时,之前的 setTimeout 已经执行过就无法「回到过去」。
|
||||
|
||||
**规则**:
|
||||
- `render(t)` 函数理想上是 **pure function**:给定 t 输出唯一 DOM 状态
|
||||
- 如果必须用副作用(如 class 切换),用 `fired` set 配合显式 reset:
|
||||
```js
|
||||
const fired = new Set();
|
||||
function fireOnce(key, fn) { if (!fired.has(key)) { fired.add(key); fn(); } }
|
||||
function reset() { fired.clear(); /* 清所有 .show class */ }
|
||||
```
|
||||
- 暴露 `window.__seek(t)` 供 Playwright / 调试用:
|
||||
```js
|
||||
window.__seek = (t) => { reset(); render(t); };
|
||||
```
|
||||
- 动画相关的 setTimeout 不要跨越 >1 秒,否则 seek 回跳时会乱套
|
||||
|
||||
## 6. 字体加载前测量 = 测错
|
||||
|
||||
**踩的坑**:页面一 DOMContentLoaded 就调用 `charRect(idx)` 测量 bracket 位置,字体还没加载,每个字符宽度是 fallback 字体的宽度,位置全错。等字体一加载(约 500ms 后),bracket 的 `left: Xpx` 还是老值,永久偏移。
|
||||
|
||||
**规则**:
|
||||
- 任何依赖 DOM 测量(`getBoundingClientRect`、`offsetWidth`)的布局代码,**必须**包在 `document.fonts.ready.then()` 里
|
||||
```js
|
||||
document.fonts.ready.then(() => {
|
||||
requestAnimationFrame(() => {
|
||||
buildBrackets(...); // 此时字体已就绪,测量准确
|
||||
tick(); // 动画开始
|
||||
});
|
||||
});
|
||||
```
|
||||
- 额外的 `requestAnimationFrame` 给浏览器一帧时间提交 layout
|
||||
- 如果用 Google Fonts CDN,`<link rel="preconnect">` 加速首次加载
|
||||
|
||||
## 7. 录制准备 —— 为视频导出预留抓手
|
||||
|
||||
**踩的坑**:Playwright `recordVideo` 默认 25fps,从 context 创建就开始录。页面加载、字体加载的前 2 秒都被录进去。交付时视频前面 2 秒空白/闪白。
|
||||
|
||||
**规则**:
|
||||
- 提供 `render-video.js` 工具处理:warmup navigate → reload 重启动画 → 等 duration → ffmpeg trim head + 转 H.264 MP4
|
||||
- 动画的**第 0 帧**要是最终布局已就位的完整初始状态(不是空白或加载中)
|
||||
- 想要 60fps?用 ffmpeg `minterpolate` 后处理,不指望浏览器源帧率
|
||||
- 想要 GIF?两阶段 palette(`palettegen` + `paletteuse`),对 30s 1080p 动画能压到 3MB
|
||||
|
||||
参见 `video-export.md` 获取完整脚本调用方式。
|
||||
|
||||
## 8. 批量导出 —— tmp 目录必须带 PID 防并发冲突
|
||||
|
||||
**踩的坑**:用 `render-video.js` 3 个进程并行录 3 个 HTML。因为 TMP_DIR 只用 `Date.now()` 命名,3 个进程同毫秒启动时共用同一个 tmp 目录。最先完成的进程清理 tmp,另外两个读目录时 `ENOENT`,全部崩溃。
|
||||
|
||||
**规则**:
|
||||
- 任何多进程可能共用的临时目录,命名必须带 **PID 或随机后缀**:
|
||||
```js
|
||||
const TMP_DIR = path.join(DIR, '.video-tmp-' + Date.now() + '-' + process.pid);
|
||||
```
|
||||
- 如果确实想多文件并行,用 shell 的 `&` + `wait` 而不是在一个 node 脚本里 fork
|
||||
- 批量录多个 HTML 时,保守做法:**串行**运行(2 个以内可并行,3 个以上老实排队)
|
||||
|
||||
## 9. 录屏里有进度条/重播按钮 —— Chrome 元素污染视频
|
||||
|
||||
**踩的坑**:动画 HTML 加了 `.progress` 进度条、`.replay` 重播按钮、`.counter` 时间戳,方便人类调试播放。录成 MP4 交付时这些元素出现在视频底部,像把开发者工具截进去了一样。
|
||||
|
||||
**规则**:
|
||||
- HTML 里给人类用的「chrome 元素」(progress bar / replay button / footer / masthead / counter / phase labels)和视频内容本体分开管理
|
||||
- **约定 class 名** `.no-record`:任何带这个 class 的元素,录屏脚本自动隐藏
|
||||
- 脚本端(`render-video.js`)默认注入 CSS 隐藏常见 chrome class 名:
|
||||
```
|
||||
.progress .counter .phases .replay .masthead .footer .no-record [data-role="chrome"]
|
||||
```
|
||||
- 用 Playwright 的 `addInitScript` 注入(会在每次 navigate 前生效,reload 也稳)
|
||||
- 想看原样 HTML(带 chrome)时加 `--keep-chrome` flag
|
||||
|
||||
## 10. 录屏开头几秒动画重复 —— Warmup 帧泄漏
|
||||
|
||||
**踩的坑**:`render-video.js` 的旧流程 `goto → wait fonts 1.5s → reload → wait duration`。录制从 context 创建就开始,warmup 阶段动画已经播了一段,reload 后从 0 重启。结果视频前几秒是「动画中段 + 切换 + 动画从 0 开始」,重复感强。
|
||||
|
||||
**规则**:
|
||||
- **Warmup 和 Record 必须用独立的 context**:
|
||||
- Warmup context(无 `recordVideo` 选项):只负责 load url、等字体、然后 close
|
||||
- Record context(有 `recordVideo`):fresh 状态开始,animation 从 t=0 开始录
|
||||
- ffmpeg `-ss trim` 只能裁 Playwright 的一点点 startup latency(~0.3s),**不能**用来掩盖 warmup 帧;源头要干净
|
||||
- 录制 context 关闭 = webm 文件写入磁盘,这是 Playwright 的约束
|
||||
- 相关代码模式:
|
||||
```js
|
||||
// Phase 1: warmup (throwaway)
|
||||
const warmupCtx = await browser.newContext({ viewport });
|
||||
const warmupPage = await warmupCtx.newPage();
|
||||
await warmupPage.goto(url, { waitUntil: 'networkidle' });
|
||||
await warmupPage.waitForTimeout(1200);
|
||||
await warmupCtx.close();
|
||||
|
||||
// Phase 2: record (fresh)
|
||||
const recordCtx = await browser.newContext({ viewport, recordVideo });
|
||||
const page = await recordCtx.newPage();
|
||||
await page.goto(url, { waitUntil: 'networkidle' });
|
||||
await page.waitForTimeout(DURATION * 1000);
|
||||
await page.close();
|
||||
await recordCtx.close();
|
||||
```
|
||||
|
||||
## 11. 画面内别画「伪 chrome」—— 装饰版 player UI 与真 chrome 撞车
|
||||
|
||||
**踩的坑**:动画用 `Stage` 组件,已经自带 scrubber + 时间码 + 暂停按钮(属于 `.no-record` chrome,导出时自动隐藏)。我又在画面底部画了一条「`00:60 ──── CLAUDE-DESIGN / ANATOMY`」的"杂志页码感装饰进度条",自我感觉良好。**结果**:用户看到两条进度条——一条是 Stage 控制器,一条是我画的装饰。视觉上完全撞车,认定为 bug。「视频内还有个进度条是怎么回事?」
|
||||
|
||||
**规则**:
|
||||
|
||||
- Stage 已经提供:scrubber + 时间码 + 暂停/重播按钮。**画面内不要再画**进度指示、当前时间码、版权署名条、章节计数器——它们要么和 chrome 撞车,要么就是 filler slop(违反「earn its place」原则)。
|
||||
- 「页码感」「杂志感」「底部署名条」这些**装饰诉求**,是 AI 自动加上的高频 filler。每一个出现都要警觉——它真的传达了不可替代的信息吗?还是单纯填满空白?
|
||||
- 如果你坚信某个底部条带必须存在(例如:动画主题就是讲 player UI),那它必须**叙事必要**,且**视觉上和 Stage scrubber 显著区分**(不同位置、不同形式、不同色调)。
|
||||
|
||||
**元素归属测试**(每个画进 canvas 的元素必须能回答):
|
||||
|
||||
| 它属于什么 | 处理 |
|
||||
|------------|------|
|
||||
| 某一幕的叙事内容 | OK,留着 |
|
||||
| 全局 chrome(控制/调试用) | 加 `.no-record` class,导出时隐藏 |
|
||||
| **既不属于任何幕,又不是 chrome** | **删**。这就是无主之物,必然是 filler slop |
|
||||
|
||||
**自检(交付前 3 秒)**:截一张静态图,问自己——
|
||||
|
||||
- 画面里有没有「看起来像 video player UI 的东西」(横线进度条、时间码、控制按钮模样)?
|
||||
- 如果有,删掉它叙事是否有损?无损就删。
|
||||
- 同一类信息(进度/时间/署名)有没有出现两次?合并到 chrome 一处。
|
||||
|
||||
**反例**:底部画 `00:42 ──── PROJECT NAME`、画面右下角画"CH 03 / 06"章节计数、画面边缘画版本号"v0.3.1"——都是伪 chrome filler。
|
||||
|
||||
## 12. 录屏前置空白 —— 用 `window.__ready` 同步动画 t=0
|
||||
|
||||
**踩的坑**:60 秒动画导出 MP4,前 2-3 秒是空白页面。`ffmpeg --trim=0.3` 剪不掉。
|
||||
|
||||
**根因**:Playwright `recordVideo` 从 `newContext()` 那一刻就开始写 WebM。但此时 Babel Standalone 还在编译 inline JSX、React 还没 mount、`document.fonts.ready.then(root.render)` 还没触发。`page.goto(url, { waitUntil: 'networkidle' })` 只等网络空闲,检测不到 JS 执行阶段——所以 WebM 前 1.5-3s 是空白页。
|
||||
|
||||
**规则**:
|
||||
|
||||
1. **动画代码**在 tick 第一帧发 `window.__ready = true`,和动画 t=0 同步:
|
||||
```js
|
||||
function tick(now) {
|
||||
if (last === null) {
|
||||
last = now;
|
||||
window.__ready = true; // 必须在这里,不是 useEffect
|
||||
}
|
||||
// ... 动画推进
|
||||
}
|
||||
```
|
||||
为什么同步?如果 `__ready` 在 tick 之前设(如 `useEffect` 或 rAF 排队),触发时 WebM 光标还在空白页;如果在 tick 之后设(rAF 嵌套),则动画已经跑了几帧被 trim 掉。**pair 起来**才是对的。
|
||||
|
||||
2. **录屏脚本**`page.goto` 之后 `waitForFunction(() => window.__ready === true)`,记录此时相对 WebM 起点的秒数作为 ffmpeg trim 偏移。完全不靠猜。
|
||||
|
||||
3. **字体等待**放在 tick 启动条件里:`document.fonts.ready.then(() => rAF(tick))`。这样 tick 第一帧就是字体已就绪的画面——`__ready` 信号 = WebM 捕到的第一个"用户会看到"的动画帧。
|
||||
|
||||
**不这么做的代价**:固定 trim 靠猜。机器快慢、字体缓存状态、网速每次不同——某台机器上的 3s trim 换到另一台可能不够或截掉开头。动态测量从根本解决。
|
||||
|
||||
**参考实现**:`assets/animations.jsx` 的 Stage 组件已内置。`scripts/render-video.js` 已内置 auto-trim 逻辑。非 animations.jsx 的手写 HTML,自行在 tick/渲染循环的第一帧设信号。
|
||||
|
||||
**验证方法**:导出后 `ffmpeg -i video.mp4 -ss 0 -vframes 1 frame-0.png`,检查第一帧是动画应有的初始状态(不是动画中段、不是黑屏)。
|
||||
|
||||
## 快速自查清单(开工前 5 秒)
|
||||
|
||||
- [ ] 每个 `position: absolute` 的父元素都有 `position: relative`?
|
||||
- [ ] 动画里的特殊字符(`␣` `⌘` `emoji`)都在字体里存在?
|
||||
- [ ] Grid/Flex 模板的 count 和 JS 数据的 length 一致?
|
||||
- [ ] 场景切换之间有 cross-fade,没有 >0.3s 的纯空白?
|
||||
- [ ] DOM 测量代码包在 `document.fonts.ready.then()` 里?
|
||||
- [ ] `render(t)` 是 pure 的,或有明确的 reset 机制?
|
||||
- [ ] 第 0 帧是完整初始状态,不是空白?
|
||||
- [ ] 画面内没有「伪 chrome」装饰(进度条/时间码/底部署名条与 Stage scrubber 撞车)?
|
||||
- [ ] 动画 tick 第一帧同步设 `window.__ready = true`?(用 animations.jsx 自带;手写 HTML 自己加)
|
||||
- [ ] 导出后抽第 0 帧验证是动画初始状态?
|
||||
@@ -0,0 +1,246 @@
|
||||
# Animations:时间轴动画引擎
|
||||
|
||||
做动画/motion design HTML时读这个。原理、用法、典型模式。
|
||||
|
||||
## 核心模式:Stage + Sprite
|
||||
|
||||
我们的动画系统(`assets/animations.jsx`)提供一个时间轴驱动的引擎:
|
||||
|
||||
- **`<Stage>`**:整个动画的容器,自动提供auto-scale(fit viewport)+ scrubber + play/pause/loop控制
|
||||
- **`<Sprite start end>`**:时间片段。一个Sprite只在`start`到`end`这段时间内显示。内部可以通过`useSprite()` hook读取自己的本地进度`t` (0→1)
|
||||
- **`useTime()`**:读当前全局时间(秒)
|
||||
- **`Easing.easeInOut` / `Easing.easeOut` / ...**:缓动函数
|
||||
- **`interpolate(t, from, to, easing?)`**:根据t插值
|
||||
|
||||
这套模式借鉴Remotion/After Effects思路,但轻量、零依赖。
|
||||
|
||||
## 起手
|
||||
|
||||
```html
|
||||
<script type="text/babel" src="animations.jsx"></script>
|
||||
<script type="text/babel">
|
||||
const { Stage, Sprite, useTime, useSprite, Easing, interpolate } = window.Animations;
|
||||
|
||||
function Title() {
|
||||
const { t } = useSprite(); // 本地进度 0→1
|
||||
const opacity = interpolate(t, [0, 1], [0, 1], Easing.easeOut);
|
||||
const y = interpolate(t, [0, 1], [40, 0], Easing.easeOut);
|
||||
return (
|
||||
<h1 style={{
|
||||
opacity,
|
||||
transform: `translateY(${y}px)`,
|
||||
fontSize: 120,
|
||||
fontWeight: 900,
|
||||
}}>
|
||||
Hello.
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
||||
function Scene() {
|
||||
return (
|
||||
<Stage duration={10}> {/* 10秒动画 */}
|
||||
<Sprite start={0} end={3}>
|
||||
<Title />
|
||||
</Sprite>
|
||||
<Sprite start={2} end={5}>
|
||||
<SubTitle />
|
||||
</Sprite>
|
||||
{/* ... */}
|
||||
</Stage>
|
||||
);
|
||||
}
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(<Scene />);
|
||||
</script>
|
||||
```
|
||||
|
||||
## 常用动画模式
|
||||
|
||||
### 1. Fade In / Fade Out
|
||||
|
||||
```jsx
|
||||
function FadeIn({ children }) {
|
||||
const { t } = useSprite();
|
||||
const opacity = interpolate(t, [0, 0.3], [0, 1], Easing.easeOut);
|
||||
return <div style={{ opacity }}>{children}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
**注意范围**:`[0, 0.3]`意思是在sprite的前30%时间完成渐入,后面保持opacity=1。
|
||||
|
||||
### 2. Slide In
|
||||
|
||||
```jsx
|
||||
function SlideIn({ children, from = 'left' }) {
|
||||
const { t } = useSprite();
|
||||
const progress = interpolate(t, [0, 0.4], [0, 1], Easing.easeOut);
|
||||
const offset = (1 - progress) * 100;
|
||||
const directions = {
|
||||
left: `translateX(-${offset}px)`,
|
||||
right: `translateX(${offset}px)`,
|
||||
top: `translateY(-${offset}px)`,
|
||||
bottom: `translateY(${offset}px)`,
|
||||
};
|
||||
return (
|
||||
<div style={{
|
||||
transform: directions[from],
|
||||
opacity: progress,
|
||||
}}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 逐字打字机
|
||||
|
||||
```jsx
|
||||
function Typewriter({ text }) {
|
||||
const { t } = useSprite();
|
||||
const charCount = Math.floor(text.length * Math.min(t * 2, 1));
|
||||
return <span>{text.slice(0, charCount)}</span>;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 数字计数
|
||||
|
||||
```jsx
|
||||
function CountUp({ from = 0, to = 100, duration = 0.6 }) {
|
||||
const { t } = useSprite();
|
||||
const progress = interpolate(t, [0, duration], [0, 1], Easing.easeOut);
|
||||
const value = Math.floor(from + (to - from) * progress);
|
||||
return <span>{value.toLocaleString()}</span>;
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 分段解释(典型教学动画)
|
||||
|
||||
```jsx
|
||||
function Scene() {
|
||||
return (
|
||||
<Stage duration={20}>
|
||||
{/* Phase 1: 展示问题 */}
|
||||
<Sprite start={0} end={4}>
|
||||
<Problem />
|
||||
</Sprite>
|
||||
|
||||
{/* Phase 2: 展示思路 */}
|
||||
<Sprite start={4} end={10}>
|
||||
<Approach />
|
||||
</Sprite>
|
||||
|
||||
{/* Phase 3: 展示结果 */}
|
||||
<Sprite start={10} end={16}>
|
||||
<Result />
|
||||
</Sprite>
|
||||
|
||||
{/* 全程显示的字幕 */}
|
||||
<Sprite start={0} end={20}>
|
||||
<Caption />
|
||||
</Sprite>
|
||||
</Stage>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Easing函数
|
||||
|
||||
预设的easing curves:
|
||||
|
||||
| Easing | 特性 | 用在 |
|
||||
|--------|------|------|
|
||||
| `linear` | 匀速 | 滚动字幕、持续动画 |
|
||||
| `easeIn` | 慢→快 | 退场消失 |
|
||||
| `easeOut` | 快→慢 | 入场出现(最常用) |
|
||||
| `easeInOut` | 慢→快→慢 | 位置变化 |
|
||||
| `spring` | 弹簧 | 交互反馈 |
|
||||
| `anticipation` | 先反向再正向 | 强调动作 |
|
||||
|
||||
**入场用easeOut,出场用easeIn**——这是动画的基础规律。
|
||||
|
||||
## 节奏和时长指南
|
||||
|
||||
### 微交互(0.1-0.3秒)
|
||||
- 按钮hover
|
||||
- 卡片expand
|
||||
- Tooltip出现
|
||||
|
||||
### UI过渡(0.3-0.8秒)
|
||||
- 页面切换
|
||||
- 模态框出现
|
||||
- 列表item加入
|
||||
|
||||
### 叙事动画(2-10秒每段)
|
||||
- 概念解释的一个phase
|
||||
- 数据图表的reveal
|
||||
- 场景转换
|
||||
|
||||
### 单段叙事动画最长不超过10秒
|
||||
人类注意力有限。10秒讲一件事,讲完换下一件。
|
||||
|
||||
## 设计动画的思考顺序
|
||||
|
||||
### 1. 先有内容/故事,再有动画
|
||||
|
||||
**错误**:先想要做fancy动画,再塞内容进去
|
||||
**正确**:先想清楚要传达什么信息,再用动画手段serve这个信息
|
||||
|
||||
动画是**signal**,不是**装饰**。一个fade-in强调的是"这里很重要,请看"——如果什么都fade-in,signal就失效。
|
||||
|
||||
### 2. 分Scene写时间轴
|
||||
|
||||
```
|
||||
0:00 - 0:03 问题出现(fade in)
|
||||
0:03 - 0:06 问题放大/展开(zoom+pan)
|
||||
0:06 - 0:09 解法出现(slide in from right)
|
||||
0:09 - 0:12 解法展开说明(typewriter)
|
||||
0:12 - 0:15 结果演示(counter up + chart reveal)
|
||||
0:15 - 0:18 总结一句话(static,读3秒)
|
||||
0:18 - 0:20 CTA或fade out
|
||||
```
|
||||
|
||||
写完时间轴再写组件。
|
||||
|
||||
### 3. 资源先行
|
||||
|
||||
动画要用的图片/图标/字体**先**准备好。不要画到一半去找素材——打断节奏。
|
||||
|
||||
## 常见问题
|
||||
|
||||
**动画卡顿**
|
||||
→ 主要是layout thrashing。用`transform`和`opacity`,不要动`top`/`left`/`width`/`height`/`margin`。浏览器GPU加速`transform`。
|
||||
|
||||
**动画太快,看不清楚**
|
||||
→ 人读一个汉字需要100-150ms,一个词300-500ms。如果你用文字讲故事,单句至少留3秒。
|
||||
|
||||
**动画太慢,观众无聊**
|
||||
→ 有趣的视觉变化要密集。静态画面超过5秒就会闷。
|
||||
|
||||
**多个动画互相影响**
|
||||
→ 用CSS的`will-change: transform`提前告诉浏览器这个元素会动,减少reflow。
|
||||
|
||||
**录制成视频**
|
||||
→ 用 skill 自带工具链(一条命令出三种格式):见 `video-export.md`
|
||||
- `scripts/render-video.js` — HTML → 25fps MP4(Playwright + ffmpeg)
|
||||
- `scripts/convert-formats.sh` — 25fps MP4 → 60fps MP4 + 优化 GIF
|
||||
- 想要更精确的帧渲染?让 render(t) 成为 pure function,见 `animation-pitfalls.md` 第 5 条
|
||||
|
||||
## 和视频工具的配合
|
||||
|
||||
这个skill做的是**HTML动画**(在浏览器里跑的)。如果最终产出要作为视频素材:
|
||||
|
||||
- **短动画/concept demo**:用这里的方法做HTML动画 → 屏幕录制
|
||||
- **长视频/叙事**:本 skill 专注 HTML 动画,长视频用 AI 视频生成类 skill 或专业视频软件
|
||||
- **motion graphics**:专业的After Effects/Motion Canvas更合适
|
||||
|
||||
## 关于Popmotion等库
|
||||
|
||||
如果你真的需要物理动画(spring、decay、keyframes with precise timing),我们的engine搞不定,可以fallback到Popmotion:
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/popmotion@11.0.5/dist/popmotion.min.js"></script>
|
||||
```
|
||||
|
||||
但**先试试我们的engine**。90%的情况够用。
|
||||
@@ -0,0 +1,260 @@
|
||||
# Content Guidelines:反AI slop、内容准则、Scale规范
|
||||
|
||||
AI设计里最容易掉进去的陷阱。这是一份「不做什么」的清单,比「做什么」更重要——因为AI slop是默认值,你不主动避免就会发生。
|
||||
|
||||
## AI Slop 完整黑名单
|
||||
|
||||
### 视觉陷阱
|
||||
|
||||
**❌ 激进渐变背景**
|
||||
- 紫色 → 粉色 → 蓝色 全屏渐变(AI生成网页的典型味道)
|
||||
- 任何方向的rainbow gradient
|
||||
- Mesh gradient铺满背景
|
||||
- ✅ 如果要用渐变:subtle、单色系、有意图地点缀(比如button hover)
|
||||
|
||||
**❌ 圆角卡片 + 左border accent色**
|
||||
```css
|
||||
/* 这是AI味卡片的典型签名 */
|
||||
.card {
|
||||
border-radius: 12px;
|
||||
border-left: 4px solid #3b82f6;
|
||||
padding: 16px;
|
||||
}
|
||||
```
|
||||
这种卡片在AI生成的Dashboard里泛滥。想做强调?用更有设计感的方式:背景色对比、字重/字号对比、plain分隔线、或者干脆不分卡片。
|
||||
|
||||
**❌ Emoji 装饰**
|
||||
除非品牌本身使用emoji(比如Notion、Slack),否则不要在UI上放emoji。**尤其不要**:
|
||||
- 标题前的 🚀 ⚡️ ✨ 🎯 💡
|
||||
- Feature列表的 ✅
|
||||
- CTA按钮里的 →(箭头单独出现OK,emoji箭头不行)
|
||||
|
||||
没图标用真icon库(Lucide/Heroicons/Phosphor),或者用placeholder。
|
||||
|
||||
**❌ SVG 画 imagery**
|
||||
不要试图用SVG画:人物、场景、设备、物品、抽象艺术。AI画的SVG imagery一眼就是AI味,幼稚且廉价。**一个灰色矩形+"插画位 1200×800"的文字标签,比一个拙劣的SVG hero illustration强100倍**。
|
||||
|
||||
唯一可以用SVG的场景:
|
||||
- 真正的icon(16×16到32×32级别)
|
||||
- 几何图形做装饰元素
|
||||
- Data viz的chart
|
||||
|
||||
**❌ 过多iconography**
|
||||
不是每个标题/feature/section都需要icon。滥用icon会让界面像toy。Less is more。
|
||||
|
||||
**❌ "Data slop"**
|
||||
编造的stats装饰:
|
||||
- "10,000+ happy customers" (你都不知道有没有)
|
||||
- "99.9% uptime" (没有真数据就别写)
|
||||
- 用图标+数字+词组成的装饰"metric cards"
|
||||
- Mock table里的假数据装点得花里胡哨
|
||||
|
||||
如果没真数据,留placeholder或问用户要。
|
||||
|
||||
**❌ "Quote slop"**
|
||||
编造的用户评价、名人名言装饰页面。留placeholder问用户要真quote。
|
||||
|
||||
### 字体陷阱
|
||||
|
||||
**❌ 避免这些烂大街字体**:
|
||||
- Inter(AI生成的网页默认)
|
||||
- Roboto
|
||||
- Arial / Helvetica
|
||||
- 纯system font stack
|
||||
- Fraunces(AI发现了这个就用滥了)
|
||||
- Space Grotesk(最近AI的最爱)
|
||||
|
||||
**✅ 用有特点的display+body配对**。灵感方向:
|
||||
- 衬线display + 无衬线body(editorial feel)
|
||||
- Mono display + sans body(technical feel)
|
||||
- Heavy display + light body(contrast)
|
||||
- Variable font做hero的粗细动画
|
||||
|
||||
字体资源:
|
||||
- Google Fonts的冷门好选项(Instrument Serif、Cormorant、Bricolage Grotesque、JetBrains Mono)
|
||||
- 开源字体站(Fraunces的兄弟字体、Adobe Fonts)
|
||||
- 不要凭空发明字体名
|
||||
|
||||
### 色彩陷阱
|
||||
|
||||
**❌ 凭空发明颜色**
|
||||
不要从头设计一整套不熟悉的色彩。这通常不和谐。
|
||||
|
||||
**✅ 策略**:
|
||||
1. 有品牌色 → 用品牌色,缺的color token用oklch插值
|
||||
2. 没有品牌色但有参考 → 从参考产品截图吸色
|
||||
3. 完全从零 → 选一个known的配色系统(Radix Colors / Tailwind默认palette / Anthropic brand),不要自己调
|
||||
|
||||
**oklch定义色彩**是最现代的做法:
|
||||
```css
|
||||
:root {
|
||||
--primary: oklch(0.65 0.18 25); /* 温暖的terracotta */
|
||||
--primary-light: oklch(0.85 0.08 25); /* 同色系浅色 */
|
||||
--primary-dark: oklch(0.45 0.20 25); /* 同色系深色 */
|
||||
}
|
||||
```
|
||||
oklch能保证调整亮度时色相不漂移,比hsl好用。
|
||||
|
||||
**❌ 夜间模式随手加反色**
|
||||
不是简单invert颜色。好的dark mode需要重新调整饱和度、对比度、accent色。不想做dark mode就别做。
|
||||
|
||||
### Layout陷阱
|
||||
|
||||
**❌ Bento grid 过度泛滥**
|
||||
每个AI生成的landing page都想搞bento。除非你的信息structure确实适合bento,否则用其他layout。
|
||||
|
||||
**❌ 大hero + 3-column features + testimonials + CTA**
|
||||
这个landing page模板被用烂了。想创新就真创新。
|
||||
|
||||
**❌ Card grid里每个card长一样**
|
||||
Asymmetric、不同大小的cards、有的带image有的只有文字、有的跨列——这才像真设计师做的。
|
||||
|
||||
## 内容准则
|
||||
|
||||
### 1. Don't add filler content
|
||||
|
||||
每个元素都必须earn its place。空白是设计问题,用**构图**解决(对比、节奏、留白),**不是**靠内容填满。
|
||||
|
||||
**判断filler的问题**:
|
||||
- 如果去掉这段内容,设计会变差吗?答案若是"不会",就去掉。
|
||||
- 这个元素解决了什么真问题?如果是"让页面不那么空",删掉。
|
||||
- 这个stats/quote/feature有真数据支持吗?没有就不要凭空写。
|
||||
|
||||
「One thousand no's for every yes」。
|
||||
|
||||
### 2. Ask before adding material
|
||||
|
||||
你觉得多加一段/一页/一个section会更好?先问用户,不要单方面加。
|
||||
|
||||
原因:
|
||||
- 用户知道他的受众比你清楚
|
||||
- 加内容有成本,用户可能不想要
|
||||
- 单方面加内容违反了"junior designer汇报工作"的关系
|
||||
|
||||
### 3. Create a system up front
|
||||
|
||||
探索完design context后,**先口头说出你要用的系统**,让用户确认:
|
||||
|
||||
```markdown
|
||||
我的设计系统:
|
||||
- 色彩:#1A1A1A主体 + #F0EEE6背景 + #D97757 accent(来自你的品牌)
|
||||
- 字型:Instrument Serif做display + Geist Sans做body
|
||||
- 节奏:section title用full-bleed彩色背景 + 白字;普通section用白背景
|
||||
- 图像:hero用full-bleed照片,feature section用placeholder等你提供
|
||||
- 最多用2种背景色,避免杂乱
|
||||
|
||||
确认这个方向我就开始做。
|
||||
```
|
||||
|
||||
用户确认后再动手。这个check-in能避免"做完一半发现方向错"。
|
||||
|
||||
## Scale 规范
|
||||
|
||||
### 幻灯片(1920×1080)
|
||||
|
||||
- 正文最小 **24px**,理想 28-36px
|
||||
- 标题 60-120px
|
||||
- Section title 80-160px
|
||||
- Hero headline 可以用 180-240px 的大字
|
||||
- 永远不要用 <24px 的字放幻灯片
|
||||
|
||||
### 印刷文档
|
||||
|
||||
- 正文最小 **10pt**(≈13.3px),理想 11-12pt
|
||||
- 标题 18-36pt
|
||||
- Caption 8-9pt
|
||||
|
||||
### Web和移动端
|
||||
|
||||
- 正文最小 **14px**(老年人友好用16px)
|
||||
- 移动端正文 **16px**(避免iOS自动缩放)
|
||||
- Hit target(可点击元素)最小 **44×44px**
|
||||
- 行高 1.5-1.7(中文1.7-1.8)
|
||||
|
||||
### 对比度
|
||||
|
||||
- 正文 vs 背景 **至少 4.5:1**(WCAG AA)
|
||||
- 大字 vs 背景 **至少 3:1**
|
||||
- 用Chrome DevTools的accessibility工具检查
|
||||
|
||||
## CSS 神器
|
||||
|
||||
**高级CSS特性**是设计师的好朋友,大胆用:
|
||||
|
||||
### 排版
|
||||
|
||||
```css
|
||||
/* 让标题换行更自然,不会最后一行孤单单一个词 */
|
||||
h1, h2, h3 { text-wrap: balance; }
|
||||
|
||||
/* 正文换行,避免寡孀和孤儿 */
|
||||
p { text-wrap: pretty; }
|
||||
|
||||
/* 中文排版神器:标点挤压、行首行尾控制 */
|
||||
p {
|
||||
text-spacing-trim: space-all;
|
||||
hanging-punctuation: first;
|
||||
}
|
||||
```
|
||||
|
||||
### Layout
|
||||
|
||||
```css
|
||||
/* CSS Grid + named areas = 可读性爆表 */
|
||||
.layout {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"header header"
|
||||
"sidebar main"
|
||||
"footer footer";
|
||||
grid-template-columns: 240px 1fr;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
}
|
||||
|
||||
/* Subgrid对齐卡片内容 */
|
||||
.card { display: grid; grid-template-rows: subgrid; }
|
||||
```
|
||||
|
||||
### 视觉效果
|
||||
|
||||
```css
|
||||
/* 有设计感的滚动条 */
|
||||
* { scrollbar-width: thin; scrollbar-color: #666 transparent; }
|
||||
|
||||
/* 玻璃拟态(克制使用) */
|
||||
.glass {
|
||||
backdrop-filter: blur(20px) saturate(150%);
|
||||
background: color-mix(in oklch, white 70%, transparent);
|
||||
}
|
||||
|
||||
/* View transitions API让页面切换丝滑 */
|
||||
@view-transition { navigation: auto; }
|
||||
```
|
||||
|
||||
### 交互
|
||||
|
||||
```css
|
||||
/* :has()选择器让条件样式变容易 */
|
||||
.card:has(img) { padding-top: 0; } /* 有图片的卡片无顶padding */
|
||||
|
||||
/* container queries让组件真的响应式 */
|
||||
@container (min-width: 500px) { ... }
|
||||
|
||||
/* 新的color-mix函数 */
|
||||
.button:hover {
|
||||
background: color-mix(in oklch, var(--primary) 85%, black);
|
||||
}
|
||||
```
|
||||
|
||||
## 决策速查:当你犹豫时
|
||||
|
||||
- 想加个渐变?→ 大概率不加
|
||||
- 想加个emoji?→ 不加
|
||||
- 想给卡片加圆角+border-left accent?→ 不加,换其他方式
|
||||
- 想用SVG画个hero插画?→ 不画,用placeholder
|
||||
- 想加一段quote装饰?→ 先问用户有没有真quote
|
||||
- 想加一排icon features?→ 先问要不要icon,可能不需要
|
||||
- 用Inter?→ 换一个更有特点的
|
||||
- 用紫色渐变?→ 换一个有根据的配色
|
||||
|
||||
**当你觉得"加一下会更好看"的时候——那通常是AI slop的征兆**。先做最简的版本,只在用户要求时加。
|
||||
@@ -0,0 +1,199 @@
|
||||
# 设计评审深度指南
|
||||
|
||||
> Phase 7 的详细参考。提供评分标准、场景侧重点、常见问题清单。
|
||||
|
||||
---
|
||||
|
||||
## 评分标准详解
|
||||
|
||||
### 1. 哲学一致性(Philosophy Alignment)
|
||||
|
||||
| 分数 | 标准 |
|
||||
|------|------|
|
||||
| 9-10 | 设计完美体现了选定哲学的核心精神,每个细节都有哲学依据 |
|
||||
| 7-8 | 整体方向正确,核心特征到位,个别细节偏离 |
|
||||
| 5-6 | 能看出意图,但执行时混入了其他风格元素,不够纯粹 |
|
||||
| 3-4 | 仅在表面模仿,未理解哲学内核 |
|
||||
| 1-2 | 与选定哲学基本无关 |
|
||||
|
||||
**评审要点**:
|
||||
- 是否使用了该设计师/机构的标志性手法?
|
||||
- 色彩、字体、布局是否符合该哲学体系?
|
||||
- 有没有「自相矛盾」的元素?(如选了Kenya Hara却塞满内容)
|
||||
|
||||
### 2. 视觉层级(Visual Hierarchy)
|
||||
|
||||
| 分数 | 标准 |
|
||||
|------|------|
|
||||
| 9-10 | 用户视线自然沿设计者意图流动,信息获取零摩擦 |
|
||||
| 7-8 | 主次关系清晰,偶有1-2处层级模糊 |
|
||||
| 5-6 | 能分出标题和正文,但中间层级混乱 |
|
||||
| 3-4 | 信息平铺,没有明确的视觉入口 |
|
||||
| 1-2 | 混乱,用户不知道先看哪里 |
|
||||
|
||||
**评审要点**:
|
||||
- 标题与正文的字号对比是否足够?(至少2.5倍)
|
||||
- 颜色/粗细/大小是否建立了3-4个清晰层级?
|
||||
- 留白是否在引导视线?
|
||||
- 「眯眼测试」:眯起眼看,层级是否仍然清晰?
|
||||
|
||||
### 3. 细节执行(Craft Quality)
|
||||
|
||||
| 分数 | 标准 |
|
||||
|------|------|
|
||||
| 9-10 | 像素级精确,对齐、间距、颜色无任何瑕疵 |
|
||||
| 7-8 | 整体精致,有1-2处微小对齐/间距问题 |
|
||||
| 5-6 | 基本对齐,但间距不统一,颜色使用不够系统 |
|
||||
| 3-4 | 明显的对齐错误、间距混乱、颜色过多 |
|
||||
| 1-2 | 粗糙,看起来像草稿 |
|
||||
|
||||
**评审要点**:
|
||||
- 是否使用了统一的间距系统(如8pt网格)?
|
||||
- 同类元素的间距是否一致?
|
||||
- 颜色数量是否受控?(通常不超过3-4种)
|
||||
- 字体家族是否统一?(通常不超过2种)
|
||||
- 边缘对齐是否精确?
|
||||
|
||||
### 4. 功能性(Functionality)
|
||||
|
||||
| 分数 | 标准 |
|
||||
|------|------|
|
||||
| 9-10 | 每个设计元素都服务于目标,零冗余 |
|
||||
| 7-8 | 功能导向明确,有少量可删减的装饰 |
|
||||
| 5-6 | 基本可用,但有明显的装饰性元素分散注意力 |
|
||||
| 3-4 | 形式大于功能,用户需要努力寻找信息 |
|
||||
| 1-2 | 完全被装饰淹没,失去了传达信息的能力 |
|
||||
|
||||
**评审要点**:
|
||||
- 删掉任何一个元素,设计会变差吗?(如果不会,就应该删)
|
||||
- CTA/关键信息是否在最显眼的位置?
|
||||
- 是否有「因为好看所以加上去」的元素?
|
||||
- 信息密度与载体是否匹配?(PPT不宜太密,PDF可以更密)
|
||||
|
||||
### 5. 创新性(Originality)
|
||||
|
||||
| 分数 | 标准 |
|
||||
|------|------|
|
||||
| 9-10 | 令人耳目一新,在该哲学框架内找到了独特表达 |
|
||||
| 7-8 | 有自己的想法,不是简单的模板套用 |
|
||||
| 5-6 | 中规中矩,看起来像模板 |
|
||||
| 3-4 | 大量使用了cliché(如渐变圆球代表AI) |
|
||||
| 1-2 | 完全是模板或素材拼凑 |
|
||||
|
||||
**评审要点**:
|
||||
- 是否避免了常见cliché?(见下方「常见问题清单」)
|
||||
- 在遵循设计哲学的同时是否有个人表达?
|
||||
- 是否有「意想不到但很合理」的设计决策?
|
||||
|
||||
---
|
||||
|
||||
## 场景评审侧重
|
||||
|
||||
不同输出类型的评审重点不同:
|
||||
|
||||
| 场景 | 最重要维度 | 次重要 | 可放宽 |
|
||||
|------|-----------|--------|--------|
|
||||
| 公众号封面/配图 | 创新性、视觉层级 | 哲学一致性 | 功能性(单图不涉及交互) |
|
||||
| 信息图 | 功能性、视觉层级 | 细节执行 | 创新性(准确优先) |
|
||||
| PPT/Keynote | 视觉层级、功能性 | 细节执行 | 创新性(清晰优先) |
|
||||
| PDF/白皮书 | 细节执行、功能性 | 视觉层级 | 创新性(专业优先) |
|
||||
| 落地页/官网 | 功能性、视觉层级 | 创新性 | —(全面要求) |
|
||||
| App UI | 功能性、细节执行 | 视觉层级 | 哲学一致性(可用性优先) |
|
||||
| 小红书配图 | 创新性、视觉层级 | 哲学一致性 | 细节执行(氛围优先) |
|
||||
|
||||
---
|
||||
|
||||
## 常见设计问题 Top 10
|
||||
|
||||
### 1. AI科技cliché
|
||||
**问题**:渐变圆球、数字雨、蓝色电路板、机器人脸
|
||||
**为什么是问题**:用户已经对这些视觉疲劳,无法区分你和其他人
|
||||
**修复**:用抽象隐喻替代直白符号(如用「对话」的隐喻而非聊天气泡图标)
|
||||
|
||||
### 2. 字号层级不足
|
||||
**问题**:标题和正文差距太小(<2.5倍)
|
||||
**为什么是问题**:用户无法快速定位关键信息
|
||||
**修复**:标题至少为正文的3倍(如正文16px → 标题48-64px)
|
||||
|
||||
### 3. 颜色过多
|
||||
**问题**:使用5种以上颜色,没有主次
|
||||
**为什么是问题**:视觉混乱,品牌感弱
|
||||
**修复**:限制为1个主色+1个辅色+1个强调色+灰阶
|
||||
|
||||
### 4. 间距不统一
|
||||
**问题**:元素间距随意,没有系统
|
||||
**为什么是问题**:看起来不专业,视觉节奏混乱
|
||||
**修复**:建立8pt网格系统(间距只用8/16/24/32/48/64px)
|
||||
|
||||
### 5. 留白不足
|
||||
**问题**:所有空间都被内容填满
|
||||
**为什么是问题**:信息拥挤导致阅读疲劳,反而降低信息传达效率
|
||||
**修复**:留白至少占总面积40%(极简风格60%+)
|
||||
|
||||
### 6. 字体过多
|
||||
**问题**:使用3种以上字体
|
||||
**为什么是问题**:视觉噪音,削弱统一感
|
||||
**修复**:最多2种字体(1种标题+1种正文),用字重和大小创造变化
|
||||
|
||||
### 7. 对齐不一致
|
||||
**问题**:有的左对齐,有的居中,有的右对齐
|
||||
**为什么是问题**:破坏视觉秩序感
|
||||
**修复**:选定一种对齐方式(推荐左对齐),全局统一
|
||||
|
||||
### 8. 装饰大于内容
|
||||
**问题**:背景图案/渐变/阴影抢了主要内容的风头
|
||||
**为什么是问题**:本末倒置,用户来看信息不是看装饰
|
||||
**修复**:「如果删掉这个装饰,设计会变差吗?」如果不会,就删
|
||||
|
||||
### 9. 赛博霓虹滥用
|
||||
**问题**:深蓝底(#0D1117) + 霓虹色发光效果
|
||||
**为什么是问题**:默认审美禁区(本 skill 的品位基线),且已成为最大 cliché 之一——用户可按自己品牌 override
|
||||
**修复**:选择更有辨识度的配色方案(参考20种风格的色彩系统)
|
||||
|
||||
### 10. 信息密度与载体不匹配
|
||||
**问题**:PPT里放了一整页文字 / 封面图里塞了10个元素
|
||||
**为什么是问题**:不同载体的最佳信息密度不同
|
||||
**修复**:
|
||||
- PPT:每页1个核心观点
|
||||
- 封面图:1个视觉焦点
|
||||
- 信息图:分层展示
|
||||
- PDF:可以更密,但需要清晰的导航
|
||||
|
||||
---
|
||||
|
||||
## 评审输出模板
|
||||
|
||||
```
|
||||
## 设计评审报告
|
||||
|
||||
**总体评分**:X.X/10 [优秀(8+)/良好(6-7.9)/需改进(4-5.9)/不合格(<4)]
|
||||
|
||||
**分项评分**:
|
||||
- 哲学一致性:X/10 [一句话说明]
|
||||
- 视觉层级:X/10 [一句话说明]
|
||||
- 细节执行:X/10 [一句话说明]
|
||||
- 功能性:X/10 [一句话说明]
|
||||
- 创新性:X/10 [一句话说明]
|
||||
|
||||
### 优点(Keep)
|
||||
- [具体指出做得好的地方,用设计语言描述]
|
||||
|
||||
### 问题(Fix)
|
||||
[按严重程度排序]
|
||||
|
||||
**1. [问题名称]** — ⚠️致命 / ⚡重要 / 💡优化
|
||||
- 当前:[描述现状]
|
||||
- 问题:[为什么这是问题]
|
||||
- 修复:[具体操作,含数值]
|
||||
|
||||
### 快速修复清单(Quick Wins)
|
||||
如果只有5分钟,优先做这3件事:
|
||||
- [ ] [最有影响力的修复]
|
||||
- [ ] [第二重要的修复]
|
||||
- [ ] [第三重要的修复]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**版本**:v1.0
|
||||
**更新日期**:2026-02-13
|
||||
@@ -0,0 +1,213 @@
|
||||
# Design Context:从已有上下文出发
|
||||
|
||||
**这是这个skill最重要的one thing。**
|
||||
|
||||
好的hi-fi设计一定是从已有design context长出来的。**凭空做hi-fi是last resort,一定会产出generic的作品**。所以每次设计任务开始,先问:有没有可以参考的东西?
|
||||
|
||||
## 什么是Design Context
|
||||
|
||||
按优先级从高到低:
|
||||
|
||||
### 1. 用户的Design System/UI Kit
|
||||
用户自己产品已有的组件库、色彩token、字型规范、icon系统。**最完美的情况**。
|
||||
|
||||
### 2. 用户的Codebase
|
||||
如果用户给了代码库,里面就有活生生的组件实现。Read那些组件文件:
|
||||
- `theme.ts` / `colors.ts` / `tokens.css` / `_variables.scss`
|
||||
- 具体的组件(Button.tsx、Card.tsx)
|
||||
- Layout scaffold(App.tsx、MainLayout.tsx)
|
||||
- Global stylesheets
|
||||
|
||||
**读代码抄exact values**:hex codes、spacing scale、font stack、border radius。不要凭记忆重画。
|
||||
|
||||
### 3. 用户已发布的产品
|
||||
如果用户有上线的产品但没给代码,用Playwright或让用户提供截图。
|
||||
|
||||
```bash
|
||||
# 用Playwright截图一个公开URL
|
||||
npx playwright screenshot https://example.com screenshot.png --viewport-size=1920,1080
|
||||
```
|
||||
|
||||
让你看到真实的视觉vocabulary。
|
||||
|
||||
### 4. 品牌指南/Logo/已有素材
|
||||
用户可能有:Logo文件、品牌色规范、营销物料、slide模板。这些都是context。
|
||||
|
||||
### 5. 竞品参考
|
||||
用户说"像XX网站那样"——让他提供URL或截图。**不要**凭你训练数据里的模糊印象做。
|
||||
|
||||
### 6. 已知的design system(fallback)
|
||||
如果以上都没有,用公认的设计系统作为base:
|
||||
- Apple HIG
|
||||
- Material Design 3
|
||||
- Radix Colors(配色)
|
||||
- shadcn/ui(组件)
|
||||
- Tailwind默认palette
|
||||
|
||||
明确告诉用户你用的什么,让他知道这是起点不是定稿。
|
||||
|
||||
## 获取Context的流程
|
||||
|
||||
### Step 1:问用户
|
||||
|
||||
任务开始时的必问清单(来自`workflow.md`):
|
||||
|
||||
```markdown
|
||||
1. 你有现成的design system/UI kit/组件库吗?在哪?
|
||||
2. 有品牌指南、色彩/字体规范吗?
|
||||
3. 可以给我现有产品的截图或URL吗?
|
||||
4. 有codebase我可以读吗?
|
||||
```
|
||||
|
||||
### Step 2:用户说"没有"时,帮他找
|
||||
|
||||
别直接放弃。尝试:
|
||||
|
||||
```markdown
|
||||
让我看看有没有线索:
|
||||
- 你之前的项目有相关设计吗?
|
||||
- 公司的marketing网站用什么色彩/字型?
|
||||
- 你产品的Logo什么风格?能给我一张吗?
|
||||
- 有什么你欣赏的产品作为参考?
|
||||
```
|
||||
|
||||
### Step 3:Read所有能找到的context
|
||||
|
||||
如果用户给了codebase路径,你读:
|
||||
1. **先list文件结构**:找style/theme/component相关的文件
|
||||
2. **读theme/token文件**:lift具体的hex/px values
|
||||
3. **读2-3个代表性组件**:看视觉vocabulary(hover state、shadow、border、padding node pattern)
|
||||
4. **读global stylesheet**:基础重置、font loading
|
||||
5. **如果有Figma链接/截图**:看图,但**更相信代码**
|
||||
|
||||
**重要**:**不要**看了一眼就凭印象做。读下来有30+个具体values才真的lift到了。
|
||||
|
||||
### Step 4:Vocalize你要用的系统
|
||||
|
||||
看完context后,告诉用户你要用的系统:
|
||||
|
||||
```markdown
|
||||
根据你的codebase和产品截图,我提炼的设计系统:
|
||||
|
||||
**色彩**
|
||||
- Primary: #C27558(从tokens.css)
|
||||
- Background: #FDF9F0
|
||||
- Text: #1A1A1A
|
||||
- Muted: #6B6B6B
|
||||
|
||||
**字型**
|
||||
- Display: Instrument Serif(从global.css的@font-face)
|
||||
- Body: Geist Sans
|
||||
- Mono: JetBrains Mono
|
||||
|
||||
**Spacing**(来自你的scale系统)
|
||||
- 4, 8, 12, 16, 24, 32, 48, 64
|
||||
|
||||
**Shadow pattern**
|
||||
- `0 1px 2px rgba(0,0,0,0.04)`(subtle card)
|
||||
- `0 10px 40px rgba(0,0,0,0.1)`(elevated modal)
|
||||
|
||||
**Border-radius**
|
||||
- 小组件 4px,卡片 12px,按钮 8px
|
||||
|
||||
**component vocabulary**
|
||||
- Button:filled primary,outlined secondary,ghost tertiary,全部圆角8px
|
||||
- Card:白色背景,subtle shadow,无border
|
||||
|
||||
我按这套系统开始做。确认没问题?
|
||||
```
|
||||
|
||||
用户确认后再动手。
|
||||
|
||||
## 凭空做设计(没Context时的 fallback)
|
||||
|
||||
**强烈警告**:这种情况下的产出质量会显著下降。明确告诉用户。
|
||||
|
||||
```markdown
|
||||
你没有design context,我就只能基于通用直觉做。
|
||||
产出会是"看起来OK但缺乏独特性"的东西。
|
||||
你愿意继续,还是先补一些参考材料?
|
||||
```
|
||||
|
||||
用户执意要你做,按这个顺序做决策:
|
||||
|
||||
### 1. 选一个aesthetic direction
|
||||
不要给generic结果。挑一个明确方向:
|
||||
- brutally minimal
|
||||
- editorial/magazine
|
||||
- brutalist/raw
|
||||
- organic/natural
|
||||
- luxury/refined
|
||||
- playful/toy
|
||||
- retro-futuristic
|
||||
- soft/pastel
|
||||
|
||||
告诉用户你选了哪个。
|
||||
|
||||
### 2. 选一个known design system作为骨架
|
||||
- 用Radix Colors做配色(https://www.radix-ui.com/colors)
|
||||
- 用shadcn/ui做组件vocabulary(https://ui.shadcn.com)
|
||||
- 用Tailwind spacing scale(4的倍数)
|
||||
|
||||
### 3. 选有特点的字体配对
|
||||
|
||||
不要用Inter/Roboto。建议组合(从Google Fonts白嫖):
|
||||
- Instrument Serif + Geist Sans
|
||||
- Cormorant Garamond + Inter Tight
|
||||
- Bricolage Grotesque + Söhne(付费)
|
||||
- Fraunces + Work Sans(注意Fraunces已经被AI用烂)
|
||||
- JetBrains Mono + Geist Sans(technical feel)
|
||||
|
||||
### 4. 每个关键决策都有reasoning
|
||||
|
||||
不要默默选。在HTML的comment里写:
|
||||
|
||||
```html
|
||||
<!--
|
||||
Design decisions:
|
||||
- Primary color: warm terracotta (oklch 0.65 0.18 25) — fits the "editorial" direction
|
||||
- Display: Instrument Serif for humanist, literary feel
|
||||
- Body: Geist Sans for cleanness contrast
|
||||
- No gradients — committed to minimal, no AI slop
|
||||
- Spacing: 8px base, golden ratio friendly (8/13/21/34)
|
||||
-->
|
||||
```
|
||||
|
||||
## Import策略(用户给了codebase)
|
||||
|
||||
如果用户说"import这个codebase做参考":
|
||||
|
||||
### 小型(<50文件)
|
||||
全部Read,把context内化。
|
||||
|
||||
### 中型(50-500文件)
|
||||
Focus在:
|
||||
- `src/components/` 或 `components/`
|
||||
- 所有styles/tokens/theme相关的文件
|
||||
- 2-3个代表性的整页组件(Home.tsx、Dashboard.tsx)
|
||||
|
||||
### 大型(>500文件)
|
||||
让用户指明focus:
|
||||
- "我要做settings页面" → 读现有的settings相关
|
||||
- "我要做一个新的feature" → 读整体shell + 最接近的参考
|
||||
- 不求全,求准
|
||||
|
||||
## 和Figma/设计稿的配合
|
||||
|
||||
如果用户给了Figma链接:
|
||||
|
||||
- **不要**期望你能直接"转Figma为HTML"——那需要额外工具
|
||||
- Figma链接通常不公开可访问
|
||||
- 让用户:导出为**截图**发给你 + 告诉你具体的color/spacing values
|
||||
|
||||
如果只给了Figma截图,告诉用户:
|
||||
- 我能看到视觉,但取不到精确values
|
||||
- 关键数字(hex、px)请告诉我,或者export as code(Figma支持)
|
||||
|
||||
## 最后的提醒
|
||||
|
||||
**一个项目的设计质量上限,由你拿到的context质量决定**。
|
||||
|
||||
花10分钟收集context,比花1小时凭空画hi-fi更有价值。
|
||||
|
||||
**遇到没context的情况,优先问用户要,而不是硬上**。
|
||||
@@ -0,0 +1,591 @@
|
||||
# 设计哲学风格库:20种体系
|
||||
|
||||
> 用于视觉设计(网页/PPT/PDF/信息图/配图/App等)的设计风格库。
|
||||
> 每种风格提供:哲学内核 + 核心特征 + 提示词DNA(与场景模板组合使用)。
|
||||
|
||||
## 风格×场景×执行路径 速查表
|
||||
|
||||
| 风格 | 网页 | PPT | PDF | 信息图 | 封面 | AI生成 | 最佳路径 |
|
||||
|------|:---:|:---:|:---:|:-----:|:---:|:-----:|---------|
|
||||
| 01 Pentagram | ★★★ | ★★★ | ★★☆ | ★★☆ | ★★★ | ★☆☆ | HTML |
|
||||
| 02 Stamen Design | ★★☆ | ★★☆ | ★★☆ | ★★★ | ★★☆ | ★★☆ | 混合 |
|
||||
| 03 Information Architects | ★★★ | ★☆☆ | ★★★ | ★☆☆ | ★☆☆ | ★☆☆ | HTML |
|
||||
| 04 Fathom | ★★☆ | ★★★ | ★★★ | ★★★ | ★★☆ | ★☆☆ | HTML |
|
||||
| 05 Locomotive | ★★★ | ★★☆ | ★☆☆ | ★☆☆ | ★★☆ | ★★☆ | 混合 |
|
||||
| 06 Active Theory | ★★★ | ★☆☆ | ★☆☆ | ★☆☆ | ★★☆ | ★★★ | AI生成 |
|
||||
| 07 Field.io | ★★☆ | ★★☆ | ★☆☆ | ★★☆ | ★★★ | ★★★ | AI生成 |
|
||||
| 08 Resn | ★★★ | ★☆☆ | ★☆☆ | ★☆☆ | ★★☆ | ★★☆ | AI生成 |
|
||||
| 09 Experimental Jetset | ★★☆ | ★★☆ | ★★☆ | ★★☆ | ★★★ | ★★☆ | 混合 |
|
||||
| 10 Müller-Brockmann | ★★☆ | ★★★ | ★★★ | ★★★ | ★★☆ | ★☆☆ | HTML |
|
||||
| 11 Build | ★★★ | ★★★ | ★★☆ | ★☆☆ | ★★★ | ★☆☆ | HTML |
|
||||
| 12 Sagmeister & Walsh | ★★☆ | ★★★ | ★☆☆ | ★★☆ | ★★★ | ★★★ | AI生成 |
|
||||
| 13 Zach Lieberman | ★☆☆ | ★☆☆ | ★☆☆ | ★★☆ | ★★★ | ★★★ | AI生成 |
|
||||
| 14 Raven Kwok | ★☆☆ | ★★☆ | ★☆☆ | ★★☆ | ★★★ | ★★★ | AI生成 |
|
||||
| 15 Ash Thorp | ★★☆ | ★★☆ | ★☆☆ | ★☆☆ | ★★★ | ★★★ | AI生成 |
|
||||
| 16 Territory Studio | ★★☆ | ★★☆ | ★☆☆ | ★★☆ | ★★★ | ★★★ | AI生成 |
|
||||
| 17 Takram | ★★★ | ★★★ | ★★★ | ★★☆ | ★★☆ | ★☆☆ | HTML |
|
||||
| 18 Kenya Hara | ★★☆ | ★★★ | ★★★ | ★☆☆ | ★★★ | ★☆☆ | HTML |
|
||||
| 19 Irma Boom | ★☆☆ | ★★☆ | ★★★ | ★★☆ | ★★★ | ★★☆ | 混合 |
|
||||
| 20 Neo Shen | ★★☆ | ★★☆ | ★★☆ | ★★☆ | ★★★ | ★★★ | AI生成 |
|
||||
|
||||
> 场景适配:★★★ = 强烈推荐 / ★★☆ = 适合 / ★☆☆ = 需改造
|
||||
> AI生成:★★★ = 直出效果好 / ★★☆ = 需调整 / ★☆☆ = 建议HTML执行
|
||||
> 最佳路径:AI生成(图片直出)/ HTML(代码渲染,数据精确)/ 混合(HTML布局+AI配图)
|
||||
|
||||
**核心规律**:有明确视觉元素的风格(插画/粒子/生成艺术)AI直出效果好;依赖精确排版和数据的风格(网格/信息架构/留白)HTML渲染更可控。
|
||||
|
||||
---
|
||||
|
||||
## 一、信息建筑派(01-04)
|
||||
> 哲学:「数据不是装饰,是建筑材料」
|
||||
|
||||
### 01. Pentagram - Michael Bierut风格
|
||||
**哲学**:字体即语言,网格即思想
|
||||
**核心特征**:
|
||||
- 极度克制的颜色(黑白+1个品牌色)
|
||||
- 瑞士网格系统的现代演绎
|
||||
- 字体排印作为主要视觉语言
|
||||
- 负空间的战略性使用(60%+留白)
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Pentagram/Michael Bierut style:
|
||||
- Extreme typographic hierarchy, Helvetica/Univers family
|
||||
- Swiss grid with precise mathematical spacing
|
||||
- Black/white + one accent color (#HEX)
|
||||
- Information architecture as visual structure
|
||||
- 60%+ whitespace ratio
|
||||
- Data visualization as primary decoration
|
||||
```
|
||||
|
||||
**代表作**:Hillary Clinton 2016 campaign identity
|
||||
**搜索关键词**:pentagram hillary logo system
|
||||
|
||||
---
|
||||
|
||||
### 02. Stamen Design - 数据诗学
|
||||
**哲学**:让数据成为可触摸的风景
|
||||
**核心特征**:
|
||||
- 地图学思维应用于信息设计
|
||||
- 算法生成的有机图形
|
||||
- 温暖的数据可视化色调(赭石、鼠尾草绿、深蓝)
|
||||
- 可交互的层级系统
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Stamen Design aesthetic:
|
||||
- Cartographic approach to data visualization
|
||||
- Organic, algorithm-generated patterns
|
||||
- Warm palette (terracotta, sage green, deep blues)
|
||||
- Layered information like topographic maps
|
||||
- Hand-crafted feel despite digital precision
|
||||
- Soft shadows and depth
|
||||
```
|
||||
|
||||
**代表作**:COVID-19 surge map
|
||||
**搜索关键词**:stamen covid map visualization
|
||||
|
||||
---
|
||||
|
||||
### 03. Information Architects - 内容优先原则
|
||||
**哲学**:设计不是装饰,是内容的建筑
|
||||
**核心特征**:
|
||||
- 极端的内容层级清晰度
|
||||
- 只使用系统字体(优化阅读)
|
||||
- 蓝色超链接传统的坚守
|
||||
- 性能即美学
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Information Architects philosophy:
|
||||
- Content-first hierarchy, zero decorative elements
|
||||
- System fonts only (SF Pro/Roboto/Inter)
|
||||
- Classic blue hyperlinks (#0000EE)
|
||||
- Reading-optimized line length (66 characters)
|
||||
- Progressive disclosure of depth
|
||||
- Text-heavy, fast-loading design
|
||||
```
|
||||
|
||||
**代表作**:iA Writer app
|
||||
**搜索关键词**:information architects ia writer
|
||||
|
||||
---
|
||||
|
||||
### 04. Fathom Information Design - 科学叙事
|
||||
**哲学**:每一个像素都必须承载信息
|
||||
**核心特征**:
|
||||
- 科学期刊的严谨+设计的优雅
|
||||
- 定量数据的精确可视化
|
||||
- 冷静的专业色调(灰、海军蓝)
|
||||
- 注释与引用系统的设计化
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Fathom Information Design style:
|
||||
- Scientific journal aesthetic meets modern design
|
||||
- Precise data visualization (charts, timelines, scatter plots)
|
||||
- Neutral scheme (grays, navy, one highlight color)
|
||||
- Footnote/citation design integrated into layout
|
||||
- Clean sans-serif (GT America/Graphik)
|
||||
- Information density without clutter
|
||||
```
|
||||
|
||||
**代表作**:Bill & Melinda Gates Foundation年度报告
|
||||
**搜索关键词**:fathom information design gates foundation
|
||||
|
||||
---
|
||||
|
||||
## 二、运动诗学派(05-08)
|
||||
> 哲学:「技术本身就是一种流动的诗」
|
||||
|
||||
### 05. Locomotive - 滚动叙事大师
|
||||
**哲学**:滚动不是浏览,是旅程
|
||||
**核心特征**:
|
||||
- 丝滑的视差滚动
|
||||
- 电影化的分镜叙事
|
||||
- 大胆的空间留白
|
||||
- 动态元素的精确编排
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Locomotive scroll narrative style:
|
||||
- Film-like scene composition with parallax depth
|
||||
- Generous vertical spacing between sections
|
||||
- Bold typography emerging from darkness
|
||||
- Smooth motion blur effects
|
||||
- Dark mode (near-black backgrounds)
|
||||
- Strategic glowing accents
|
||||
- Hero sections 100vh tall
|
||||
```
|
||||
|
||||
**代表作**:Lusion.co website
|
||||
**搜索关键词**:locomotive scroll lusion
|
||||
|
||||
---
|
||||
|
||||
### 06. Active Theory - WebGL诗人
|
||||
**哲学**:让技术可见化即让技术可理解
|
||||
**核心特征**:
|
||||
- 3D粒子系统作为核心元素
|
||||
- 实时渲染的数据可视化
|
||||
- 鼠标交互驱动的世界构建
|
||||
- 霓虹与深空的配色
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Active Theory WebGL aesthetic:
|
||||
- Particle systems representing data flow
|
||||
- 3D visualization in depth space
|
||||
- Neon gradients (cyan/magenta/electric blue) on dark
|
||||
- Mouse-reactive environment
|
||||
- Depth of field and bokeh effects
|
||||
- Floating UI with glassmorphism
|
||||
```
|
||||
|
||||
**代表作**:NASA Prospect
|
||||
**搜索关键词**:active theory nasa webgl
|
||||
|
||||
---
|
||||
|
||||
### 07. Field.io - 算法美学
|
||||
**哲学**:代码即设计师
|
||||
**核心特征**:
|
||||
- 生成艺术系统
|
||||
- 每次访问都不同的动态图形
|
||||
- 抽象几何的智能编排
|
||||
- 技术感与艺术性的平衡
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Field.io generative design style:
|
||||
- Abstract geometric patterns, algorithmically generated
|
||||
- Dynamic composition that feels computational
|
||||
- Monochromatic base with vibrant accent
|
||||
- Mathematical precision in spacing
|
||||
- Voronoi diagrams or Delaunay triangulation
|
||||
- Clean code aesthetic
|
||||
```
|
||||
|
||||
**代表作**:British Council digital installations
|
||||
**搜索关键词**:field.io generative design
|
||||
|
||||
---
|
||||
|
||||
### 08. Resn - 叙事驱动的交互
|
||||
**哲学**:每个点击都推进故事
|
||||
**核心特征**:
|
||||
- 游戏化的用户旅程
|
||||
- 强烈的情感化设计
|
||||
- 插画与代码的深度结合
|
||||
- 非线性的探索体验
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Resn interactive storytelling approach:
|
||||
- Illustrative style mixed with UI elements
|
||||
- Gamified exploration (progress indicators)
|
||||
- Warm color palette despite tech subject
|
||||
- Character-driven design
|
||||
- Scroll-triggered animations
|
||||
- Editorial illustration meets product design
|
||||
```
|
||||
|
||||
**代表作**:Resn.co.nz portfolio
|
||||
**搜索关键词**:resn interactive storytelling
|
||||
|
||||
---
|
||||
|
||||
## 三、极简主义派(09-12)
|
||||
> 哲学:「删减到无法再删」
|
||||
|
||||
### 09. Experimental Jetset - 概念极简
|
||||
**哲学**:一个想法=一个形式
|
||||
**核心特征**:
|
||||
- 单一视觉隐喻贯穿整个设计
|
||||
- 蓝/红/黄+黑白的蒙德里安色系
|
||||
- 字体即图形
|
||||
- 反商业的诚实设计
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Experimental Jetset conceptual minimalism:
|
||||
- Single visual metaphor for entire design
|
||||
- Primary colors only (red/blue/yellow) + black/white
|
||||
- Typography as main graphic element
|
||||
- Grid-based with deliberate rule-breaking
|
||||
- No photography, only type and geometry
|
||||
- Anti-commercial, honest aesthetic
|
||||
```
|
||||
|
||||
**代表作**:Whitney Museum identity
|
||||
**搜索关键词**:experimental jetset whitney responsive w
|
||||
|
||||
---
|
||||
|
||||
### 10. Müller-Brockmann传承 - 瑞士网格纯粹主义
|
||||
**哲学**:客观性即美
|
||||
**核心特征**:
|
||||
- 数学精确的网格系统(8pt基线)
|
||||
- 绝对的左对齐或居中
|
||||
- 单色或双色方案
|
||||
- 功能主义至上
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Josef Müller-Brockmann Swiss modernism:
|
||||
- Mathematical grid system (8pt baseline)
|
||||
- Strict alignment (flush left or centered)
|
||||
- Two-color maximum (black + one accent)
|
||||
- Akzidenz-Grotesk or similar rationalist typeface
|
||||
- No decorative elements
|
||||
- Timeless, objective aesthetic
|
||||
```
|
||||
|
||||
**代表作**:《Grid Systems in Graphic Design》
|
||||
**搜索关键词**:muller brockmann grid systems poster
|
||||
|
||||
---
|
||||
|
||||
### 11. Build - 当代极简品牌
|
||||
**哲学**:精致的简单比复杂更难
|
||||
**核心特征**:
|
||||
- 奢侈品级的留白(70%+)
|
||||
- 微妙的字重对比(200-600)
|
||||
- 单一强调色的战略使用
|
||||
- 呼吸感的节奏
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Build studio luxury minimalism:
|
||||
- Generous whitespace (70%+ of area)
|
||||
- Subtle typography weight shifts (200 to 600)
|
||||
- Single accent color used sparingly
|
||||
- High-end product photography aesthetic
|
||||
- Soft shadows and subtle gradients
|
||||
- Golden ratio proportions
|
||||
```
|
||||
|
||||
**代表作**:Build studio portfolio
|
||||
**搜索关键词**:build studio london branding
|
||||
|
||||
---
|
||||
|
||||
### 12. Sagmeister & Walsh - 快乐极简
|
||||
**哲学**:美即功能的情感维度
|
||||
**核心特征**:
|
||||
- 意外的色彩爆发
|
||||
- 手工感与数字的融合
|
||||
- 正能量的视觉语言
|
||||
- 实验性但可读
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Sagmeister & Walsh joyful philosophy:
|
||||
- Unexpected color bursts on minimal base
|
||||
- Handmade elements (physical objects in digital)
|
||||
- Optimistic visual language
|
||||
- Experimental typography that remains legible
|
||||
- Human warmth through imperfection
|
||||
- Mix of analog and digital aesthetics
|
||||
```
|
||||
|
||||
**代表作**:The Happy Show
|
||||
**搜索关键词**:sagmeister walsh happy show
|
||||
|
||||
---
|
||||
|
||||
## 四、实验先锋派(13-16)
|
||||
> 哲学:「打破规则即创造规则」
|
||||
|
||||
### 13. Zach Lieberman - 代码诗学
|
||||
**哲学**:编程即绘画
|
||||
**核心特征**:
|
||||
- 手绘感的算法图形
|
||||
- 实时生成艺术
|
||||
- 黑白的纯粹表达
|
||||
- 工具本身的可见性
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Zach Lieberman code-as-art style:
|
||||
- Hand-drawn aesthetic generated by code
|
||||
- Black and white only, no color
|
||||
- Real-time generative patterns
|
||||
- Sketch-like line quality
|
||||
- Visible process/grid/construction lines
|
||||
- Poetic interpretation of algorithms
|
||||
```
|
||||
|
||||
**代表作**:openFrameworks creative coding
|
||||
**搜索关键词**:zach lieberman openframeworks generative
|
||||
|
||||
---
|
||||
|
||||
### 14. Raven Kwok - 参数化美学
|
||||
**哲学**:系统的美胜过个体的美
|
||||
**核心特征**:
|
||||
- 分形与递归图形
|
||||
- 黑白高对比
|
||||
- 建筑化的信息结构
|
||||
- 东方园林的算法演绎
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Raven Kwok parametric aesthetic:
|
||||
- Fractal patterns and recursive structures
|
||||
- High-contrast black and white
|
||||
- Architectural visualization of data
|
||||
- Chinese garden principles in algorithm form
|
||||
- Intricate detail that rewards zooming
|
||||
- Processing/Creative coding aesthetic
|
||||
```
|
||||
|
||||
**代表作**:Raven Kwok generative art exhibitions
|
||||
**搜索关键词**:raven kwok processing generative art
|
||||
|
||||
---
|
||||
|
||||
### 15. Ash Thorp - 赛博诗意
|
||||
**哲学**:未来不是冰冷的,是孤独的诗
|
||||
**核心特征**:
|
||||
- 电影级的光影
|
||||
- 赛博朋克的温暖版本(橙/青,非冷蓝)
|
||||
- 故事性的概念设计
|
||||
- 工业美学的精致化
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Ash Thorp cinematic concept art:
|
||||
- Film-grade lighting and atmospheric effects
|
||||
- Warm cyberpunk (orange/teal, NOT cold blue)
|
||||
- Industrial design meets luxury
|
||||
- Narrative concept art feel
|
||||
- Volumetric lighting and god rays
|
||||
- Blade Runner warmth over Tron coldness
|
||||
```
|
||||
|
||||
**代表作**:Ghost in the Shell concept art
|
||||
**搜索关键词**:ash thorp ghost shell concept art
|
||||
|
||||
---
|
||||
|
||||
### 16. Territory Studio - 屏幕界面虚构
|
||||
**哲学**:未来UI的今日想象
|
||||
**核心特征**:
|
||||
- 科幻电影中的屏幕设计(FUI)
|
||||
- 全息投影感
|
||||
- 多层叠加的数据可视化
|
||||
- 可信的未来感
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Territory Studio FUI (Fantasy User Interface):
|
||||
- Fantasy User Interface design
|
||||
- Holographic projection aesthetics
|
||||
- Orange/amber monochrome or cyan accents
|
||||
- Multiple overlapping data layers
|
||||
- Believable future technology
|
||||
- Technical readouts and data streams
|
||||
```
|
||||
|
||||
**代表作**:Blade Runner 2049 screen graphics
|
||||
**搜索关键词**:territory studio blade runner interface
|
||||
|
||||
---
|
||||
|
||||
## 五、东方哲学派(17-20)
|
||||
> 哲学:「留白即内容」
|
||||
|
||||
### 17. Takram - 日式思辨设计
|
||||
**哲学**:技术是思考的媒介
|
||||
**核心特征**:
|
||||
- 概念原型的优雅
|
||||
- 柔和的科技感(圆角、柔和阴影)
|
||||
- 图表即艺术
|
||||
- 谦逊的精致
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Takram Japanese speculative design:
|
||||
- Elegant concept prototypes and diagrams
|
||||
- Soft tech aesthetic (rounded corners, gentle shadows)
|
||||
- Charts and diagrams as art pieces
|
||||
- Modest sophistication
|
||||
- Neutral natural colors (beige, soft gray, muted green)
|
||||
- Design as philosophical inquiry
|
||||
```
|
||||
|
||||
**代表作**:NHK Fabricated City
|
||||
**搜索关键词**:takram nhk data visualization
|
||||
|
||||
---
|
||||
|
||||
### 18. Kenya Hara - 空的设计
|
||||
**哲学**:设计不是填充,是清空
|
||||
**核心特征**:
|
||||
- 极致的留白(80%+)
|
||||
- 纸张质感的数字化
|
||||
- 白色的层次(暖白、冷白、米白)
|
||||
- 触觉的视觉化
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Kenya Hara "emptiness" design:
|
||||
- Extreme whitespace (80%+)
|
||||
- Paper texture and tactility in digital form
|
||||
- Layers of white (warm white, cool white, off-white)
|
||||
- Minimal color (if any, very desaturated)
|
||||
- Design by subtraction not addition
|
||||
- Zen simplicity
|
||||
```
|
||||
|
||||
**代表作**:Muji art direction, 《Designing Design》
|
||||
**搜索关键词**:kenya hara designing design muji
|
||||
|
||||
---
|
||||
|
||||
### 19. Irma Boom - 书籍建筑师
|
||||
**哲学**:信息的物理诗学
|
||||
**核心特征**:
|
||||
- 非线性的信息架构
|
||||
- 边缘与边界的游戏
|
||||
- 意外的颜色组合(粉+红、橙+棕)
|
||||
- 手工艺的数字转译
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Irma Boom book architecture style:
|
||||
- Non-linear information structure
|
||||
- Play with edges, margins, boundaries
|
||||
- Unexpected color combos (pink+red, orange+brown)
|
||||
- Handcraft translated to digital
|
||||
- Dense information inviting exploration
|
||||
- Editorial design, unconventional grid
|
||||
```
|
||||
|
||||
**代表作**:SHV Think Book (2136 pages)
|
||||
**搜索关键词**:irma boom shv think book
|
||||
|
||||
---
|
||||
|
||||
### 20. Neo Shen - 东方光影诗
|
||||
**哲学**:技术需要人的温度
|
||||
**核心特征**:
|
||||
- 水墨晕染的数字化
|
||||
- 柔和的光晕效果
|
||||
- 诗意的留白
|
||||
- 情感化的色彩(深蓝、暖灰、柔金)
|
||||
|
||||
**提示词DNA**:
|
||||
```
|
||||
Neo Shen poetic Chinese aesthetic:
|
||||
- Digital interpretation of ink wash painting
|
||||
- Soft glow and light diffusion effects
|
||||
- Poetic negative space
|
||||
- Emotional palette (deep blues, warm grays, soft gold)
|
||||
- Calligraphic influences in typography
|
||||
- Atmospheric depth
|
||||
```
|
||||
|
||||
**代表作**:Neo Shen digital art series
|
||||
**搜索关键词**:neo shen digital ink wash art
|
||||
|
||||
---
|
||||
|
||||
## 提示词使用说明
|
||||
|
||||
**组合公式**:`[风格提示词DNA] + [场景模板(见scene-templates.md)] + [具体内容]`
|
||||
|
||||
### 核心原则:描述情绪而非布局(Mood, Not Layout)
|
||||
|
||||
AI图像生成的关键:短提示词 > 长提示词。描述3句情绪和内容,比30行布局细节效果更好。
|
||||
|
||||
| 杀死多样性的写法 | 激发创造力的写法 |
|
||||
|----------------|----------------|
|
||||
| 指定颜色比例(60%/25%/15%) | 描述情绪("warm like Sunday morning") |
|
||||
| 规定布局位置("标题居中,图片右侧") | 引用具体美学("Pentagram editorial feel") |
|
||||
| 限制角色姿势和表情 | 让AI自然诠释风格 |
|
||||
| 列出所有要包含的视觉元素 | 描述观众应该感受到什么 |
|
||||
|
||||
### Good / Bad 示例
|
||||
|
||||
**Bad — 过度约束(AI生成出来空且平):**
|
||||
```
|
||||
Professional presentation slide. Dark background, light text.
|
||||
Title centered at top. Two columns below. Left column: bullet points.
|
||||
Right column: bar chart. Colors: navy 60%, white 30%, gold 10%.
|
||||
Font size: title 36pt, body 18pt. Margins: 40px all sides.
|
||||
```
|
||||
|
||||
**Good — 情绪驱动(生成多样且有质感):**
|
||||
```
|
||||
A data visualization that feels like a Bloomberg Businessweek
|
||||
editorial spread. The key number "28.5%" should dominate the
|
||||
composition like a headline. Warm cream tones with sharp black
|
||||
typography. The data tells a story of dramatic channel shift.
|
||||
```
|
||||
|
||||
### 执行路径选择
|
||||
|
||||
根据速查表的「最佳路径」列选择:
|
||||
- **AI生成**:有明确视觉元素的风格(06/07/12/13/14/15/16/20),用 Gemini/Midjourney 直出
|
||||
- **HTML渲染**:依赖精确排版的风格(01/03/04/10/11/17/18),代码控制数据和布局
|
||||
- **混合**:HTML做骨架布局 + AI生成配图/背景(02/05/08/09/19)
|
||||
|
||||
### 质量控制
|
||||
|
||||
1. ❌ 不要直接写 "in the style of Pentagram" → ✅ 用具体设计特征描述
|
||||
2. 文字在AI生成中常出错 → 生成后替换文字
|
||||
3. 比例易失真 → 明确指定 aspect ratio
|
||||
4. 先生成3-5个变体,选择最佳后细化
|
||||
|
||||
**默认审美禁区**(用户可按自己品牌 override):
|
||||
- ❌ 赛博霓虹/深蓝色底(#0D1117)
|
||||
- ❌ 封面图加个人署名/水印
|
||||
|
||||
---
|
||||
|
||||
**版本**:v2.1
|
||||
**更新日期**:2026-02-13
|
||||
**适用场景**:网页/PPT/PDF/信息图/封面/配图/App等所有视觉设计
|
||||
**与 image-to-slides 联动**:PPT场景可直接引用本文件风格,通过 image-to-slides skill 执行生成
|
||||
@@ -0,0 +1,276 @@
|
||||
# React + Babel 项目规范
|
||||
|
||||
用HTML+React+Babel做原型时必须遵守的技术规范。不遵守会炸。
|
||||
|
||||
## Pinned Script Tags(必须用这些版本)
|
||||
|
||||
在HTML的`<head>`里放这三个script tag,用**固定版本+integrity hash**:
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
|
||||
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
|
||||
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
||||
```
|
||||
|
||||
**不要**用`react@18`或`react@latest`这种unpinned版本——会出现版本漂移/缓存问题。
|
||||
|
||||
**不要**省略`integrity`——CDN一旦被劫持或篡改,这是防线。
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
项目名/
|
||||
├── index.html # 主HTML
|
||||
├── components.jsx # 组件文件(type="text/babel"加载)
|
||||
├── data.js # 数据文件
|
||||
└── styles.css # 额外CSS(可选)
|
||||
```
|
||||
|
||||
HTML里加载方式:
|
||||
|
||||
```html
|
||||
<!-- 先React+Babel -->
|
||||
<script src="https://unpkg.com/react@18.3.1/..."></script>
|
||||
<script src="https://unpkg.com/react-dom@18.3.1/..."></script>
|
||||
<script src="https://unpkg.com/@babel/standalone@7.29.0/..."></script>
|
||||
|
||||
<!-- 然后你的组件文件 -->
|
||||
<script type="text/babel" src="components.jsx"></script>
|
||||
<script type="text/babel" src="pages.jsx"></script>
|
||||
|
||||
<!-- 最后主入口 -->
|
||||
<script type="text/babel">
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(<App />);
|
||||
</script>
|
||||
```
|
||||
|
||||
**不要**用`type="module"`——会和Babel冲突。
|
||||
|
||||
## 三条不可违反的规矩
|
||||
|
||||
### 规矩1:styles 对象必须用唯一命名
|
||||
|
||||
**错误**(多组件时必炸):
|
||||
```jsx
|
||||
// components.jsx
|
||||
const styles = { button: {...}, card: {...} };
|
||||
|
||||
// pages.jsx ← 同名覆盖!
|
||||
const styles = { container: {...}, header: {...} };
|
||||
```
|
||||
|
||||
**正确**:每个组件文件的styles用唯一前缀。
|
||||
|
||||
```jsx
|
||||
// terminal.jsx
|
||||
const terminalStyles = {
|
||||
screen: {...},
|
||||
line: {...}
|
||||
};
|
||||
|
||||
// sidebar.jsx
|
||||
const sidebarStyles = {
|
||||
container: {...},
|
||||
item: {...}
|
||||
};
|
||||
```
|
||||
|
||||
**或者用inline styles**(小组件推荐):
|
||||
```jsx
|
||||
<div style={{ padding: 16, background: '#111' }}>...</div>
|
||||
```
|
||||
|
||||
这条是**非协商**的。每次写`const styles = {...}`都必须replace成specific命名,否则多组件加载时全栈报错。
|
||||
|
||||
### 规矩2:Scope 不共享,需手动export
|
||||
|
||||
**关键认知**:每个`<script type="text/babel">`被Babel独立编译,它们之间**scope不通**。`components.jsx`里定义的`Terminal`组件,在`pages.jsx`里**默认是undefined**。
|
||||
|
||||
**解决方式**:在每个组件文件末尾,把要共享的组件/工具export到`window`:
|
||||
|
||||
```jsx
|
||||
// components.jsx 末尾
|
||||
function Terminal(props) { ... }
|
||||
function Line(props) { ... }
|
||||
const colors = { green: '#...', red: '#...' };
|
||||
|
||||
Object.assign(window, {
|
||||
Terminal, Line, colors,
|
||||
// 所有你要在别处用的都列在这里
|
||||
});
|
||||
```
|
||||
|
||||
然后`pages.jsx`就能直接用`<Terminal />`,因为JSX会去`window.Terminal`找。
|
||||
|
||||
### 规矩3:不要用 scrollIntoView
|
||||
|
||||
`scrollIntoView`会把整个HTML容器往上推,搞坏web harness的布局。**永远不要用**。
|
||||
|
||||
替代方案:
|
||||
```js
|
||||
// 滚到容器内某个位置
|
||||
container.scrollTop = targetElement.offsetTop;
|
||||
|
||||
// 或者用element.scrollTo
|
||||
container.scrollTo({
|
||||
top: targetElement.offsetTop - 100,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
```
|
||||
|
||||
## 调 Claude API(HTML内)
|
||||
|
||||
部分原生 design-agent 环境(如 Claude.ai Artifacts)有免配置的 `window.claude.complete`,但大部分 agent 环境(Claude Code / Codex / Cursor / Trae / etc.)本地里**没有**。
|
||||
|
||||
如果你的 HTML 原型需要调用 LLM 做 demo(比如做个聊天 interface),两个选项:
|
||||
|
||||
### 选项A:不真调,用mock
|
||||
|
||||
Demo场景推荐。写一个假helper,返回预设的response:
|
||||
```jsx
|
||||
window.claude = {
|
||||
async complete(prompt) {
|
||||
await new Promise(r => setTimeout(r, 800)); // 模拟延迟
|
||||
return "这是一个mock响应。真部署时请替换为真API。";
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 选项B:真调Anthropic API
|
||||
|
||||
需要API key,用户必须在HTML里填入自己的key才能跑。**永远不要把key硬编码在HTML里**。
|
||||
|
||||
```html
|
||||
<input id="api-key" placeholder="粘贴你的Anthropic API key" />
|
||||
<script>
|
||||
window.claude = {
|
||||
async complete(prompt) {
|
||||
const key = document.getElementById('api-key').value;
|
||||
const res = await fetch('https://api.anthropic.com/v1/messages', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'x-api-key': key,
|
||||
'anthropic-version': '2023-06-01',
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'claude-haiku-4-5',
|
||||
max_tokens: 1024,
|
||||
messages: [{ role: 'user', content: prompt }]
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.content[0].text;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
**注意**:浏览器直接调Anthropic API会遇到CORS问题。如果用户给你的预览环境不支持CORS bypass,这条路不通。这时候用选项A mock,或者告诉用户需要一个proxy后端。
|
||||
|
||||
### 选项 C:用 agent 侧的 LLM 能力生成 mock 数据
|
||||
|
||||
如果只是本地演示用,可以在当前 agent 会话里临时调用该 agent 的 LLM 能力(或用户装的 multi-model 类 skill)先生成 mock 响应数据,再硬编码写进 HTML。这样 HTML 运行时完全不依赖任何 API。
|
||||
|
||||
## 典型 HTML 起手模板
|
||||
|
||||
拷贝这个模板作为React原型的骨架:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Your Prototype Name</title>
|
||||
|
||||
<!-- React + Babel pinned -->
|
||||
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
|
||||
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
|
||||
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
|
||||
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
html, body { height: 100%; width: 100%; }
|
||||
body {
|
||||
font-family: -apple-system, 'SF Pro Text', sans-serif;
|
||||
background: #FAFAFA;
|
||||
color: #1A1A1A;
|
||||
}
|
||||
#root { min-height: 100vh; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
<!-- 你的组件文件 -->
|
||||
<script type="text/babel" src="components.jsx"></script>
|
||||
|
||||
<!-- 主入口 -->
|
||||
<script type="text/babel">
|
||||
const { useState, useEffect } = React;
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div style={{padding: 40}}>
|
||||
<h1>Hello</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(<App />);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## 常见报错及解决
|
||||
|
||||
**`styles is not defined` 或 `Cannot read property 'button' of undefined`**
|
||||
→ 你在一个文件里定义了`const styles`,另一个文件覆盖了。给每个改成specific命名。
|
||||
|
||||
**`Terminal is not defined`**
|
||||
→ 跨文件引用时scope不通。在定义Terminal的文件末尾加`Object.assign(window, {Terminal})`。
|
||||
|
||||
**整个页面白屏,控制台没错误**
|
||||
→ 多半是JSX语法错误但Babel没报在控制台。把`babel.min.js`临时换成`babel.js`非压缩版,错误信息更清晰。
|
||||
|
||||
**ReactDOM.createRoot is not a function**
|
||||
→ 版本不对。确认用了react-dom@18.3.1(而不是17或其他)。
|
||||
|
||||
**`Objects are not valid as a React child`**
|
||||
→ 你渲染了一个对象而不是JSX/字符串。通常是`{someObj}`写成了`{someObj.name}`。
|
||||
|
||||
## 大项目怎么拆文件
|
||||
|
||||
**>1000行的单文件**难维护。分拆思路:
|
||||
|
||||
```
|
||||
项目/
|
||||
├── index.html
|
||||
├── src/
|
||||
│ ├── primitives.jsx # 基础元素:Button、Card、Badge...
|
||||
│ ├── components.jsx # 业务组件:UserCard、PostList...
|
||||
│ ├── pages/
|
||||
│ │ ├── home.jsx # 首页
|
||||
│ │ ├── detail.jsx # 详情页
|
||||
│ │ └── settings.jsx # 设置页
|
||||
│ ├── router.jsx # 简单路由(React state切换)
|
||||
│ └── app.jsx # 入口组件
|
||||
└── data.js # mock data
|
||||
```
|
||||
|
||||
HTML里按顺序加载:
|
||||
```html
|
||||
<script type="text/babel" src="src/primitives.jsx"></script>
|
||||
<script type="text/babel" src="src/components.jsx"></script>
|
||||
<script type="text/babel" src="src/pages/home.jsx"></script>
|
||||
<script type="text/babel" src="src/pages/detail.jsx"></script>
|
||||
<script type="text/babel" src="src/pages/settings.jsx"></script>
|
||||
<script type="text/babel" src="src/router.jsx"></script>
|
||||
<script type="text/babel" src="src/app.jsx"></script>
|
||||
```
|
||||
|
||||
**每个文件末尾**都要`Object.assign(window, {...})`导出要共享的东西。
|
||||
@@ -0,0 +1,262 @@
|
||||
# 场景模板库:按输出类型组织
|
||||
|
||||
> 与 design-styles.md 的「提示词DNA」组合使用。
|
||||
> 公式:`[风格提示词DNA] + [场景模板] + [具体内容描述]`
|
||||
|
||||
---
|
||||
|
||||
## 1. 公众号封面 / 文章题图
|
||||
|
||||
**规格**:
|
||||
- 封面图:2.35:1(900×383px 或 1200×510px)
|
||||
- 正文插图:16:9(1200×675px)或 4:3(1200×900px)
|
||||
|
||||
**关键设计要素**:
|
||||
- 视觉冲击力优先(用户在信息流中快速扫过)
|
||||
- 文字极少或无文字(公众号标题会覆盖在上面)
|
||||
- 色彩饱和度适中(微信阅读环境偏白)
|
||||
- 避免过度细节(缩略图也要可辨识)
|
||||
|
||||
**推荐风格**:01 Pentagram / 11 Build / 12 Sagmeister / 18 Kenya Hara / 07 Field.io
|
||||
|
||||
**场景提示词模板**:
|
||||
```
|
||||
[风格DNA插入此处]
|
||||
- Article cover image for WeChat subscription
|
||||
- Landscape format, 2.35:1 aspect ratio
|
||||
- Bold visual impact, minimal or no text
|
||||
- Moderate color saturation for white reading environment
|
||||
- Must remain recognizable as thumbnail
|
||||
- Clean composition with clear focal point
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 正文配图 / 概念插画
|
||||
|
||||
**规格**:
|
||||
- 16:9(1200×675px)最通用
|
||||
- 1:1(800×800px)适合强调
|
||||
- 4:3(1200×900px)适合信息密集
|
||||
|
||||
**关键设计要素**:
|
||||
- 服务于文章论点,不是装饰
|
||||
- 与上下文形成视觉节奏
|
||||
- 简洁表达一个核心概念
|
||||
- AI生成优先,HTML截图仅在精确数据表格时用
|
||||
|
||||
**推荐风格**:根据文章调性选择,常用 01/04/10/17/18
|
||||
|
||||
**场景提示词模板**:
|
||||
```
|
||||
[风格DNA插入此处]
|
||||
- Article illustration, concept visualization
|
||||
- [16:9 / 1:1 / 4:3] aspect ratio
|
||||
- Single clear concept: [描述核心概念]
|
||||
- Serve the argument, not decoration
|
||||
- [Light/Dark] background to match article tone
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 信息图 / 数据可视化
|
||||
|
||||
**规格**:
|
||||
- 竖版长图:1080×1920px(手机阅读)
|
||||
- 横版:1920×1080px(文章内嵌)
|
||||
- 方形:1080×1080px(社交媒体)
|
||||
|
||||
**关键设计要素**:
|
||||
- 信息层级清晰(标题 → 核心数据 → 细节)
|
||||
- 数据准确,不编造
|
||||
- 视觉引导线(用户阅读路径)
|
||||
- 适当使用图标/图表辅助理解
|
||||
|
||||
**推荐风格**:04 Fathom / 10 Müller-Brockmann / 02 Stamen / 17 Takram
|
||||
|
||||
**场景提示词模板**:
|
||||
```
|
||||
[风格DNA插入此处]
|
||||
- Infographic / data visualization
|
||||
- [Vertical 1080x1920 / Horizontal 1920x1080 / Square 1080x1080]
|
||||
- Clear information hierarchy: title → key data → details
|
||||
- Visual flow guiding reader's eye path
|
||||
- Icons and charts for comprehension
|
||||
- Data-accurate, no decorative distortion
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. PPT / Keynote 演示
|
||||
|
||||
**规格**:
|
||||
- 标准:16:9(1920×1080px)
|
||||
- 宽屏:16:10(1920×1200px)
|
||||
|
||||
**关键设计要素**:
|
||||
- 每页一个核心信息(不堆砌)
|
||||
- 字号层级明确(标题40pt+ / 正文24pt+ / 注释16pt+)
|
||||
- 大量留白,投影时更清晰
|
||||
- 图文比例至少 60:40
|
||||
- 一致的视觉系统(颜色、字体、间距)
|
||||
|
||||
**推荐风格**:01 Pentagram / 10 Müller-Brockmann / 11 Build / 18 Kenya Hara / 04 Fathom
|
||||
|
||||
**场景提示词模板**:
|
||||
```
|
||||
[风格DNA插入此处]
|
||||
- Presentation slide design, 16:9
|
||||
- One core message per slide
|
||||
- Clear type hierarchy (title 40pt+, body 24pt+)
|
||||
- Generous whitespace for projection clarity
|
||||
- Consistent visual system throughout
|
||||
- [Light/Dark] theme
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. PDF 白皮书 / 技术报告
|
||||
|
||||
**规格**:
|
||||
- A4 纵向(210×297mm / 595×842pt)
|
||||
- Letter 纵向(216×279mm / 612×792pt)
|
||||
|
||||
**关键设计要素**:
|
||||
- 长文阅读优化(行宽66字符、行高1.5-1.8)
|
||||
- 清晰的章节导航系统
|
||||
- 页眉/页脚/页码的统一设计
|
||||
- 图表与正文的优雅共存
|
||||
- 引用/注释系统
|
||||
- 封面页设计精致
|
||||
|
||||
**推荐风格**:10 Müller-Brockmann / 04 Fathom / 03 Information Architects / 17 Takram / 19 Irma Boom
|
||||
|
||||
**场景提示词模板**:
|
||||
```
|
||||
[风格DNA插入此处]
|
||||
- PDF document / white paper design
|
||||
- A4 portrait format (210×297mm)
|
||||
- Long-form reading optimized (66 char line width, 1.5 line height)
|
||||
- Clear chapter navigation system
|
||||
- Elegant header/footer/page number design
|
||||
- Charts integrated with body text
|
||||
- Professional cover page
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 落地页 / 产品官网
|
||||
|
||||
**规格**:
|
||||
- Desktop: 1440px 宽度设计(响应至320px)
|
||||
- 首屏高度:100vh
|
||||
|
||||
**关键设计要素**:
|
||||
- 首屏5秒内传达核心价值
|
||||
- 清晰的CTA(行动按钮)
|
||||
- 滚动叙事结构(问题→方案→证明→行动)
|
||||
- 移动端适配
|
||||
- 加载速度
|
||||
|
||||
**推荐风格**:05 Locomotive / 01 Pentagram / 11 Build / 08 Resn / 06 Active Theory
|
||||
|
||||
**场景提示词模板**:
|
||||
```
|
||||
[风格DNA插入此处]
|
||||
- Landing page / product website
|
||||
- Desktop 1440px width, responsive
|
||||
- Hero section 100vh, core value in 5 seconds
|
||||
- Clear CTA button design
|
||||
- Scroll narrative: problem → solution → proof → action
|
||||
- Modern web aesthetic
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. App UI / 原型界面
|
||||
|
||||
**规格**:
|
||||
- iOS: 390×844pt(iPhone 15)
|
||||
- Android: 360×800dp
|
||||
- 平板: 1024×1366pt(iPad Pro)
|
||||
|
||||
**关键设计要素**:
|
||||
- 触摸友好(最小点击区44×44pt)
|
||||
- 系统设计语言一致性
|
||||
- 状态栏/导航栏/Tab栏的标准处理
|
||||
- 信息密度适中(移动端不宜过密)
|
||||
|
||||
**推荐风格**:17 Takram / 11 Build / 03 Information Architects / 01 Pentagram
|
||||
|
||||
**场景提示词模板**:
|
||||
```
|
||||
[风格DNA插入此处]
|
||||
- Mobile app UI design
|
||||
- iOS [390×844pt] / Android [360×800dp]
|
||||
- Touch-friendly (44pt minimum tap targets)
|
||||
- Consistent design system
|
||||
- Standard status bar / navigation / tab bar
|
||||
- Moderate information density
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 小红书配图
|
||||
|
||||
**规格**:
|
||||
- 竖版:3:4(1080×1440px)最佳
|
||||
- 方形:1:1(1080×1080px)
|
||||
- 首图决定点击率
|
||||
|
||||
**关键设计要素**:
|
||||
- 视觉吸引力第一(在瀑布流中竞争)
|
||||
- 可以有少量文字(但不超过画面20%)
|
||||
- 色彩鲜明但不俗
|
||||
- 生活感/质感/氛围感
|
||||
|
||||
**推荐风格**:12 Sagmeister / 11 Build / 20 Neo Shen / 09 Experimental Jetset
|
||||
|
||||
**场景提示词模板**:
|
||||
```
|
||||
[风格DNA插入此处]
|
||||
- Social media image for Xiaohongshu (RED)
|
||||
- Vertical 3:4 (1080×1440px)
|
||||
- Eye-catching in waterfall feed
|
||||
- Minimal text overlay (under 20% of area)
|
||||
- Vivid but tasteful colors
|
||||
- Lifestyle/texture/atmosphere feel
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 组合示例
|
||||
|
||||
**场景**:公众号封面,介绍一款AI编程工具,想要专业但有温度
|
||||
|
||||
**Step 1**:选风格 → 17 Takram(专业+温度)
|
||||
**Step 2**:取Takram提示词DNA + 公众号封面模板
|
||||
|
||||
```
|
||||
Takram Japanese speculative design:
|
||||
- Elegant concept prototypes and diagrams
|
||||
- Soft tech aesthetic (rounded corners, gentle shadows)
|
||||
- Charts and diagrams as art pieces
|
||||
- Modest sophistication
|
||||
- Neutral natural colors (beige, soft gray, muted green)
|
||||
- Design as philosophical inquiry
|
||||
|
||||
Article cover image for WeChat subscription
|
||||
- Landscape format, 2.35:1 aspect ratio (1200×510px)
|
||||
- Bold visual impact, minimal text
|
||||
- Moderate color saturation for white reading environment
|
||||
- Must remain recognizable as thumbnail
|
||||
- Clean composition with clear focal point
|
||||
|
||||
Content: An AI coding assistant tool, showing the concept of human-AI collaboration
|
||||
in software development, warm and professional atmosphere
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**版本**:v1.0
|
||||
**更新日期**:2026-02-13
|
||||
@@ -0,0 +1,429 @@
|
||||
# Slide Decks:HTML幻灯片制作规范
|
||||
|
||||
做幻灯片是设计工作的高频场景。这份文档说明怎么做好HTML幻灯片。
|
||||
|
||||
**和huashu-slides skill的区别**:huashu-slides focus on「AI演示文稿全流程」(含PPT导出);本文档focus on「用HTML本身作为呈现媒介」的设计方法论。两者可以配合使用——用这里的方法做高质量的HTML deck,再用huashu-slides导出成PPTX。
|
||||
|
||||
---
|
||||
|
||||
## 🛑 先定架构:单文件 还是 多文件?
|
||||
|
||||
**这个选择是做幻灯片的第一步,错了会反复踩坑。先读完这一节再动手。**
|
||||
|
||||
### 两种架构对比
|
||||
|
||||
| 维度 | 单文件 + `deck_stage.js` | **多文件 + `deck_index.html` 拼接器** |
|
||||
|------|--------------------------|--------------------------------------|
|
||||
| 代码结构 | 一个 HTML,所有 slide 是 `<section>` | 每页独立 HTML,`index.html` 用 iframe 拼接 |
|
||||
| CSS 作用域 | ❌ 全局,一页的样式可能影响所有页 | ✅ 天然隔离,iframe 各自一片天 |
|
||||
| 验证粒度 | ❌ 要 JS goTo 才能切到某页 | ✅ 单页文件双击就能在浏览器看 |
|
||||
| 并行开发 | ❌ 一个文件,多 agent 改会冲突 | ✅ 多 agent 可并行做不同页,零冲突 merge |
|
||||
| 调试难度 | ❌ 一处 CSS 出错,全 deck 翻车 | ✅ 一页出错只影响自己 |
|
||||
| 内嵌交互 | ✅ 跨页共享状态很简单 | 🟡 iframe 间需 postMessage |
|
||||
| 打印 PDF | ✅ 内置 | ✅ 拼接器 beforeprint 遍历 iframe |
|
||||
| 键盘导航 | ✅ 内置 | ✅ 拼接器内置 |
|
||||
|
||||
### 选哪个?(决策树)
|
||||
|
||||
```
|
||||
│ 问:deck 预计有多少页?
|
||||
├── ≤10 页、需要 in-deck 动画或跨页交互、pitch deck → 单文件
|
||||
└── ≥10 页、学术讲座、课件、长 deck、多 agent 并行 → 多文件(推荐)
|
||||
```
|
||||
|
||||
**默认走多文件路径**。它不是「备选」,是**长 deck 和团队协作的主路径**。原因:单文件架构的每一个优势(键盘导航、打印、scale)多文件都有,而多文件的作用域隔离和可验证性是单文件补不回来的。
|
||||
|
||||
### 为什么这条规则这么硬?(真实事故记录)
|
||||
|
||||
单文件架构曾经在 AI心理学讲座 deck 制作中连踩四坑:
|
||||
|
||||
1. **CSS 特异性覆盖**:`.emotion-slide { display: grid }` (特异性 10) 干翻 `deck-stage > section { display: none }` (特异性 2),导致所有页同时渲染叠加。
|
||||
2. **Shadow DOM slot 规则被外层 CSS 压制**:`::slotted(section) { display: none }` 挡不住 outer rule 的覆盖,sections 不肯隐藏。
|
||||
3. **localStorage + hash 导航竞态**:刷新后不是跳到 hash 位置,而是停在 localStorage 记录的旧位置。
|
||||
4. **验证成本高**:必须 `page.evaluate(d => d.goTo(n))` 才能截某页,比直接 `goto(file://.../slides/05-X.html)` 慢一倍,还常报错。
|
||||
|
||||
全部根因是**单一全局命名空间**——多文件架构从物理层面把这些问题消除了。
|
||||
|
||||
---
|
||||
|
||||
## 路径 A(默认):多文件架构
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
我的Deck/
|
||||
├── index.html # 从 assets/deck_index.html 复制来,改 MANIFEST
|
||||
├── shared/
|
||||
│ ├── tokens.css # 共享设计 token(色板/字号/常用 chrome)
|
||||
│ └── fonts.html # <link> 引入 Google Fonts(每页 include)
|
||||
└── slides/
|
||||
├── 01-cover.html # 每个文件都是完整 1920×1080 HTML
|
||||
├── 02-agenda.html
|
||||
├── 03-problem.html
|
||||
└── ...
|
||||
```
|
||||
|
||||
### 每张 slide 的模板骨架
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>P05 · Chapter Title</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=..." rel="stylesheet">
|
||||
<link rel="stylesheet" href="../shared/tokens.css">
|
||||
<style>
|
||||
/* 这一页独有的样式。用任何 class 名都不会污染别的页。*/
|
||||
body { padding: 120px; }
|
||||
.my-thing { ... }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 1920×1080 的内容(由 body 的 width/height 在 tokens.css 里锁定)-->
|
||||
<div class="page-header">...</div>
|
||||
<div>...</div>
|
||||
<div class="page-footer">...</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
**关键约束**:
|
||||
- `<body>` 就是画布,直接在上面布局。不要包 `<section>` 或其他 wrapper。
|
||||
- `width: 1920px; height: 1080px` 由 `shared/tokens.css` 里的 `body` 规则锁定。
|
||||
- 引 `shared/tokens.css` 共享设计 token(色板、字号、page-header/footer 等)。
|
||||
- 字体 `<link>` 每页自己写(fonts 单独 import 不贵,且保证每页独立可打开)。
|
||||
|
||||
### 拼接器:`deck_index.html`
|
||||
|
||||
**直接从 `assets/deck_index.html` 复制**。你只需要改一处——`window.DECK_MANIFEST` 数组,按顺序列出所有 slide 文件名和人类可读标签:
|
||||
|
||||
```js
|
||||
window.DECK_MANIFEST = [
|
||||
{ file: "slides/01-cover.html", label: "封面" },
|
||||
{ file: "slides/02-agenda.html", label: "目录" },
|
||||
{ file: "slides/03-problem.html", label: "问题陈述" },
|
||||
// ...
|
||||
];
|
||||
```
|
||||
|
||||
拼接器已内置:键盘导航(←/→/Home/End/数字键/P 打印)、scale + letterbox、右下计数器、localStorage 记忆、hash 跳页、打印模式(遍历 iframe 按页输出 PDF)。
|
||||
|
||||
### 单页验证(这是多文件架构的杀手级优势)
|
||||
|
||||
每张 slide 都是独立 HTML。**做完一张就在浏览器双击打开看**:
|
||||
|
||||
```bash
|
||||
open slides/05-personas.html
|
||||
```
|
||||
|
||||
Playwright 截图也是直接 `goto(file://.../slides/05-personas.html)`,不需要 JS 跳页,也不会被别的页的 CSS 干扰。这让「改一点验一点」的工作流成本接近零。
|
||||
|
||||
### 并行开发
|
||||
|
||||
把每张 slide 的任务拆给不同 agent,同时跑——HTML 文件彼此独立,merge 时没有冲突。长 deck 用这种并行方式能把制作时间压到 1/N。
|
||||
|
||||
### `shared/tokens.css` 该放什么
|
||||
|
||||
只放**真正跨页共用**的东西:
|
||||
|
||||
- CSS 变量(色板、字号阶、间距阶)
|
||||
- `body { width: 1920px; height: 1080px; }` 这样的 canvas 锁定
|
||||
- `.page-header` / `.page-footer` 这种每页都用一模一样的 chrome
|
||||
|
||||
**不要**把单页的布局 class 塞进来——那会退化回单文件架构的全局污染问题。
|
||||
|
||||
---
|
||||
|
||||
## 路径 B(小 deck):单文件 + `deck_stage.js`
|
||||
|
||||
适用于 ≤10 页、需要跨页共享状态(比如一个 React tweaks 面板要操控所有页)、或者做 pitch deck demo 这种要求极度紧凑的场景。
|
||||
|
||||
### 基本用法
|
||||
|
||||
1. 从 `assets/deck_stage.js` 读取内容,嵌入 HTML 的 `<script>`(或 `<script src="deck_stage.js">`)
|
||||
2. 在 body 里用 `<deck-stage>` 包 slide:
|
||||
|
||||
```html
|
||||
<deck-stage>
|
||||
<section>
|
||||
<h1>Slide 1</h1>
|
||||
</section>
|
||||
<section>
|
||||
<h1>Slide 2</h1>
|
||||
</section>
|
||||
</deck-stage>
|
||||
```
|
||||
|
||||
### ⚠️ 单文件架构的 CSS 陷阱(务必阅读)
|
||||
|
||||
单文件架构最常见的坑——**`display` 属性被单页样式偷走**。
|
||||
|
||||
如果你给某张 slide 的样式写了 `display: flex/grid`:
|
||||
|
||||
```css
|
||||
.emotion-slide { display: grid; } /* 特异性: 10 */
|
||||
```
|
||||
|
||||
它会压过 deck 级的「隐藏非 active 页」规则:
|
||||
|
||||
```css
|
||||
deck-stage > section { display: none; } /* 特异性: 2 */
|
||||
```
|
||||
|
||||
结果所有 slide 同时渲染叠加。
|
||||
|
||||
**修复模式**(写 deck 时必做):
|
||||
|
||||
```css
|
||||
/* ✅ 用 :not(.active) + !important 锁死「非激活即隐藏」 */
|
||||
deck-stage > section:not(.active) {
|
||||
display: none !important;
|
||||
}
|
||||
```
|
||||
|
||||
特异性+权重双保险,单页 layout class 的 `display: grid/flex` 就不会影响可见性。
|
||||
|
||||
另一个替代方案:**把单页的 flex/grid 写到内部 wrapper div 上**,section 本身只管 `display: block/none`。
|
||||
|
||||
### 自定义尺寸
|
||||
|
||||
```html
|
||||
<deck-stage width="1080" height="1920">
|
||||
<!-- 9:16 竖版 -->
|
||||
</deck-stage>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Slide Labels
|
||||
|
||||
Deck_stage 和 deck_index 都会给每页打标签(计数器显示)。给它们**更有意义**的 label:
|
||||
|
||||
**多文件**:在 `MANIFEST` 里写 `{ file, label: "04 问题陈述" }`
|
||||
**单文件**:在 section 上加 `<section data-screen-label="04 Problem Statement">`
|
||||
|
||||
**关键:Slide 编号从 1 开始,不要从 0**。
|
||||
|
||||
用户说"slide 5"时,他指的是第 5 张,永远不是数组位置 `[4]`。人类不说 0-indexed。
|
||||
|
||||
---
|
||||
|
||||
## Speaker Notes
|
||||
|
||||
**默认不加**,只在用户明确要求时才加。
|
||||
|
||||
加了 speaker notes 你就可以把 slide 上的文字减少到最小,focus on impactful visuals——notes 承载完整 script。
|
||||
|
||||
### 格式
|
||||
|
||||
**多文件**:在 `index.html` 的 `<head>` 里写:
|
||||
|
||||
```html
|
||||
<script type="application/json" id="speaker-notes">
|
||||
[
|
||||
"第1张的 script...",
|
||||
"第2张的 script...",
|
||||
"..."
|
||||
]
|
||||
</script>
|
||||
```
|
||||
|
||||
**单文件**:同上位置。
|
||||
|
||||
### Notes 写作要点
|
||||
|
||||
- **完整**:不是提纲,是真要讲的话
|
||||
- **对话式**:像平时说话,不是书面语
|
||||
- **对应**:数组第 N 个对应第 N 张 slide
|
||||
- **长度**:200-400 字最佳
|
||||
- **情绪线**:标注重音、停顿、强调点
|
||||
|
||||
---
|
||||
|
||||
## Slide 设计模式
|
||||
|
||||
### 1. 建立一个系统(必做)
|
||||
|
||||
探索完 design context 后,**先口头说你要用的系统**:
|
||||
|
||||
```markdown
|
||||
Deck系统:
|
||||
- 背景色:最多2种(90% 白 + 10% 深色 section divider)
|
||||
- 字型:display 用 Instrument Serif,body 用 Geist Sans
|
||||
- 节奏:section divider 用 full-bleed 彩色 + 白字,普通 slide 白底
|
||||
- 图像:hero slide 用 full-bleed 照片,data slide 用 chart
|
||||
|
||||
我按这个系统做,有问题告诉我。
|
||||
```
|
||||
|
||||
用户确认后再往下做。
|
||||
|
||||
### 2. 常用 slide layouts
|
||||
|
||||
- **Title slide**:纯色背景 + 巨大标题 + 副标题 + 作者/日期
|
||||
- **Section divider**:彩色背景 + 章节号 + 章节标题
|
||||
- **Content slide**:白底 + 标题 + 1-3 bullet points
|
||||
- **Data slide**:标题 + 大图表/数字 + 简短说明
|
||||
- **Image slide**:full-bleed 照片 + 底部小 caption
|
||||
- **Quote slide**:留白 + 巨大 quote + attribution
|
||||
- **Two-column**:左右对比(vs / before-after / problem-solution)
|
||||
|
||||
一个 deck 里最多用 4-5 种 layout。
|
||||
|
||||
### 3. Scale(再次强调)
|
||||
|
||||
- 正文最小 **24px**,理想 28-36px
|
||||
- 标题 **60-120px**
|
||||
- Hero 字 **180-240px**
|
||||
- 幻灯片是给 10 米外看的,字要够大
|
||||
|
||||
### 4. 视觉节奏
|
||||
|
||||
Deck 需要 **intentional variety**:
|
||||
|
||||
- 颜色节奏:大部分白底 + 偶尔彩色 section divider + 偶尔 dark 片段
|
||||
- 密度节奏:几张 text-heavy 的 + 几张 image-heavy 的 + 几张 quote 留白
|
||||
- 字号节奏:正常标题 + 偶尔巨型 hero 文字
|
||||
|
||||
**不要每张 slide 长一样**——那是 PPT 模板,不是设计。
|
||||
|
||||
### 5. 空间呼吸(数据密集页必读)
|
||||
|
||||
**新手最容易踩的坑**:把所有能放的信息都塞进一页。
|
||||
|
||||
信息密度 ≠ 有效信息传达。学术/演讲类 deck 尤其要克制:
|
||||
|
||||
- 列表/矩阵页:不要把 N 个元素都画成同一大小。用 **主次分层**——今天要聊的 5 个放大做主角,剩下 16 个缩小做背景 hint。
|
||||
- 大数字页:数字本身是视觉主角。周围的 caption 不要超过 3 行,否则观众眼球来回跳。
|
||||
- 引用页:引语和 attribution 之间要有留白隔开,不要贴在一起。
|
||||
|
||||
对照「数据是不是主角」「文字有没有挤在一起」两条自我审查,改到留白让你有点不安为止。
|
||||
|
||||
---
|
||||
|
||||
## 打印为 PDF
|
||||
|
||||
**多文件**:`deck_index.html` 已处理 `beforeprint` 事件,按页输出 PDF。
|
||||
|
||||
**单文件**:`deck_stage.js` 同样处理。
|
||||
|
||||
打印样式已写好,不需要额外写 `@media print` CSS。
|
||||
|
||||
---
|
||||
|
||||
## 导出为 PPTX / PDF(自助脚本)
|
||||
|
||||
HTML 优先是第一公民。但用户经常需要 PPTX/PDF 交付。提供两个通用脚本,**任何多文件 deck 都能用**,位于 `scripts/` 下:
|
||||
|
||||
### `export_deck_pdf.mjs` — 导出矢量 PDF(推荐)
|
||||
|
||||
```bash
|
||||
node scripts/export_deck_pdf.mjs --slides <slides-dir> --out deck.pdf
|
||||
```
|
||||
|
||||
**特点**:
|
||||
- 文字**保留矢量**(可复制、可搜索)
|
||||
- 视觉 100% 保真(Playwright 内嵌 Chromium 渲染后打印)
|
||||
- **不需要改 HTML 任何一个字**
|
||||
- 每个 slide 独立 `page.pdf()`,再用 `pdf-lib` 合并
|
||||
|
||||
**依赖**:`npm install playwright pdf-lib`
|
||||
|
||||
**限制**:PDF 不能再编辑文字——要改回到 HTML 改。
|
||||
|
||||
### `export_deck_pptx.mjs` — 导出 PPTX(两种模式)
|
||||
|
||||
```bash
|
||||
# 图片铺底(视觉 100% 保真,不可编辑文字)
|
||||
node scripts/export_deck_pptx.mjs --slides <dir> --out deck.pptx --mode image
|
||||
|
||||
# 每个文本独立文本框(可编辑,但字体会回落)
|
||||
node scripts/export_deck_pptx.mjs --slides <dir> --out deck.pptx --mode editable
|
||||
```
|
||||
|
||||
| 模式 | 视觉保真 | 文字可编辑 | 工作原理 | 限制 |
|
||||
|------|---------|----------|---------|------|
|
||||
| `image` | ✅ 100% | ❌ | Playwright 截图 → pptxgenjs addImage | 文字变图片 |
|
||||
| `editable` | 🟡 ~70% | ✅ | html2pptx 提取每个文本框 | 见下方约束 |
|
||||
|
||||
**editable 模式的硬性约束**(用户 HTML 必须满足,否则该页 skip):
|
||||
- 所有文字必须在 `<p>`/`<h1>`-`<h6>`/`<ul>`/`<ol>` 里(禁止裸文本 div)
|
||||
- `<p>`/`<h*>` 标签自身不能有 background/border/shadow(放外层 div)
|
||||
- 不用 `::before`/`::after` 插入装饰文字(伪元素提不出来)
|
||||
- inline 元素(span/em/strong)不能有 margin
|
||||
- 不用 CSS gradient(不可渲染)
|
||||
- div 不用 `background-image`(用 `<img>`)
|
||||
|
||||
脚本已内置**自动预处理器**——把 "叶子 div 里的裸文本" 自动包成 `<p>`(保留 class)。这解决了最常见的违规(裸文本)。但其他违规(p 上有 border、span 上有 margin 等)仍需 HTML 源头合规。
|
||||
|
||||
**editable 模式的另一个 caveat——字体回落**:
|
||||
- Playwright 用 webfont 测量 text-box 尺寸;PowerPoint/Keynote 用本机字体渲染
|
||||
- 两者不同时会有**溢出或错位**——每页都要肉眼过
|
||||
- 建议目标机器装好 HTML 里用的字体,或 fallback 到 `system-ui`
|
||||
|
||||
### 从一开始就让 HTML 对导出友好
|
||||
|
||||
对性能最稳的 deck:**从写 HTML 时就按 editable 模式的约束写**。这样 `--mode editable` 可以直接全部 pass。额外成本不大:
|
||||
|
||||
```html
|
||||
<!-- ❌ 不好 -->
|
||||
<div class="title">关键发现</div>
|
||||
|
||||
<!-- ✅ 好(p 包裹,class 继承) -->
|
||||
<p class="title">关键发现</p>
|
||||
|
||||
<!-- ❌ 不好(border 在 p 上) -->
|
||||
<p class="stat" style="border-left: 3px solid red;">41%</p>
|
||||
|
||||
<!-- ✅ 好(border 在外层 div) -->
|
||||
<div class="stat-wrap" style="border-left: 3px solid red;">
|
||||
<p class="stat">41%</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 何时选哪个
|
||||
|
||||
| 场景 | 推荐 |
|
||||
|------|------|
|
||||
| 给主办方/档案存档 | **PDF**(通用、高保真、文字可搜) |
|
||||
| 发给协作者让他们微调文字 | **PPTX editable**(接受字体回落) |
|
||||
| 要现场演讲、不改内容 | **PDF** 或 **PPTX image** |
|
||||
| HTML 是首选呈现媒介 | 直接浏览器播放,导出只是备份 |
|
||||
|
||||
## 导出为可编辑 PPTX 的深度路径(仅长期项目)
|
||||
|
||||
如果你的 deck 会长期维护、反复修改、团队协作——建议**一开始就按 html2pptx 约束写 HTML**,让 `--mode editable` 稳定通过。详见 `huashu-slides` skill 的 `references/prompt-templates.md` 第 2 节(4 条硬性约束)。
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
**多文件:iframe 里的页打不开 / 白屏**
|
||||
→ 检查 `MANIFEST` 的 `file` 路径是否相对 `index.html` 正确。用浏览器 DevTools 看 iframe 的 src 能否直接访问。
|
||||
|
||||
**多文件:某页样式和别页冲突**
|
||||
→ 不可能(iframe 隔离)。如果感觉冲突,那是缓存——Cmd+Shift+R 强刷。
|
||||
|
||||
**单文件:多 slide 同时渲染叠加**
|
||||
→ CSS 特异性问题。看上面「单文件架构的 CSS 陷阱」一节。
|
||||
|
||||
**单文件:缩放看起来不对**
|
||||
→ 检查是否所有 slide 直接挂在 `<deck-stage>` 下作为 `<section>`。中间不能包 `<div>`。
|
||||
|
||||
**单文件:想跳到特定 slide**
|
||||
→ URL 加 hash:`index.html#slide-5` 跳到第 5 张。
|
||||
|
||||
**两种架构都适用:字在不同屏幕下位置不一致**
|
||||
→ 用固定尺寸(1920×1080)和 `px` 单位,不要用 `vw`/`vh` 或 `%`。缩放统一处理。
|
||||
|
||||
---
|
||||
|
||||
## 验证检查清单(做完 deck 必过)
|
||||
|
||||
1. [ ] 浏览器直接打开 `index.html`(或主 HTML),检查首页无破图、字体已加载
|
||||
2. [ ] 按 → 键翻到每一页,没有空白页、没有布局错位
|
||||
3. [ ] 按 P 键打印预览,每页恰好一张 A4(或 1920×1080)且无裁切
|
||||
4. [ ] 随机选 3 页 Cmd+Shift+R 强刷,localStorage 记忆正常工作
|
||||
5. [ ] Playwright 批量截图(单页架构:遍历 `slides/*.html`;单文件架构:用 goTo 切换),人工肉眼过一遍
|
||||
6. [ ] 搜一下 `TODO` / `placeholder` 残留,确认都清理了
|
||||
@@ -0,0 +1,313 @@
|
||||
# Tweaks:设计变体实时调参
|
||||
|
||||
Tweaks是这个skill里很核心的能力——让用户不改代码就能实时切换variations/调整参数。
|
||||
|
||||
**跨 agent 环境适配**:某些 design-agent 原生环境(如 Claude.ai Artifacts)依赖 host 的 postMessage 把 tweak 值回写源码做持久化。本 skill 采用**纯前端 localStorage 方案**——效果一致(刷新保留状态),但持久化发生在浏览器 localStorage 而不是源码文件。这个方案在任何 agent 环境(Claude Code / Codex / Cursor / Trae / etc.)都能工作。
|
||||
|
||||
## 何时加 Tweaks
|
||||
|
||||
- 用户明确要求"能调参"/"多个版本切换"
|
||||
- 设计有多个variations需要对比时
|
||||
- 用户没明说,但你主观判断**加几个有启发性的tweaks能帮用户看到可能性**
|
||||
|
||||
默认推荐:**每个设计都加2-3个tweaks**(颜色主题/字号/layout变体)即使用户没要求——让用户看到可能性空间是设计服务的一部分。
|
||||
|
||||
## 实现方式(纯前端版)
|
||||
|
||||
### 基本结构
|
||||
|
||||
```jsx
|
||||
const TWEAK_DEFAULTS = {
|
||||
"primaryColor": "#D97757",
|
||||
"fontSize": 16,
|
||||
"density": "comfortable",
|
||||
"dark": false
|
||||
};
|
||||
|
||||
function useTweaks() {
|
||||
const [tweaks, setTweaks] = React.useState(() => {
|
||||
try {
|
||||
const stored = localStorage.getItem('design-tweaks');
|
||||
return stored ? { ...TWEAK_DEFAULTS, ...JSON.parse(stored) } : TWEAK_DEFAULTS;
|
||||
} catch {
|
||||
return TWEAK_DEFAULTS;
|
||||
}
|
||||
});
|
||||
|
||||
const update = (patch) => {
|
||||
const next = { ...tweaks, ...patch };
|
||||
setTweaks(next);
|
||||
try {
|
||||
localStorage.setItem('design-tweaks', JSON.stringify(next));
|
||||
} catch {}
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
setTweaks(TWEAK_DEFAULTS);
|
||||
try {
|
||||
localStorage.removeItem('design-tweaks');
|
||||
} catch {}
|
||||
};
|
||||
|
||||
return { tweaks, update, reset };
|
||||
}
|
||||
```
|
||||
|
||||
### Tweaks面板UI
|
||||
|
||||
右下角浮动面板。可折叠:
|
||||
|
||||
```jsx
|
||||
function TweaksPanel() {
|
||||
const { tweaks, update, reset } = useTweaks();
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
position: 'fixed',
|
||||
bottom: 20,
|
||||
right: 20,
|
||||
zIndex: 9999,
|
||||
}}>
|
||||
{open ? (
|
||||
<div style={{
|
||||
background: 'white',
|
||||
border: '1px solid #e5e5e5',
|
||||
borderRadius: 12,
|
||||
padding: 20,
|
||||
boxShadow: '0 10px 40px rgba(0,0,0,0.12)',
|
||||
width: 280,
|
||||
fontFamily: 'system-ui',
|
||||
fontSize: 13,
|
||||
}}>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 16,
|
||||
}}>
|
||||
<strong>Tweaks</strong>
|
||||
<button onClick={() => setOpen(false)} style={{
|
||||
border: 'none', background: 'none', cursor: 'pointer', fontSize: 16,
|
||||
}}>×</button>
|
||||
</div>
|
||||
|
||||
{/* 颜色 */}
|
||||
<label style={{ display: 'block', marginBottom: 12 }}>
|
||||
<div style={{ marginBottom: 4, color: '#666' }}>主色</div>
|
||||
<input
|
||||
type="color"
|
||||
value={tweaks.primaryColor}
|
||||
onChange={e => update({ primaryColor: e.target.value })}
|
||||
style={{ width: '100%', height: 32 }}
|
||||
/>
|
||||
</label>
|
||||
|
||||
{/* 字号slider */}
|
||||
<label style={{ display: 'block', marginBottom: 12 }}>
|
||||
<div style={{ marginBottom: 4, color: '#666' }}>字号 ({tweaks.fontSize}px)</div>
|
||||
<input
|
||||
type="range"
|
||||
min={12} max={24} step={1}
|
||||
value={tweaks.fontSize}
|
||||
onChange={e => update({ fontSize: +e.target.value })}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</label>
|
||||
|
||||
{/* 密度选项 */}
|
||||
<label style={{ display: 'block', marginBottom: 12 }}>
|
||||
<div style={{ marginBottom: 4, color: '#666' }}>密度</div>
|
||||
<select
|
||||
value={tweaks.density}
|
||||
onChange={e => update({ density: e.target.value })}
|
||||
style={{ width: '100%', padding: 6 }}
|
||||
>
|
||||
<option value="compact">紧凑</option>
|
||||
<option value="comfortable">舒适</option>
|
||||
<option value="spacious">宽松</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
{/* 暗黑模式toggle */}
|
||||
<label style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
marginBottom: 16,
|
||||
}}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={tweaks.dark}
|
||||
onChange={e => update({ dark: e.target.checked })}
|
||||
/>
|
||||
<span>暗黑模式</span>
|
||||
</label>
|
||||
|
||||
<button onClick={reset} style={{
|
||||
width: '100%',
|
||||
padding: '8px 12px',
|
||||
background: '#f5f5f5',
|
||||
border: 'none',
|
||||
borderRadius: 6,
|
||||
cursor: 'pointer',
|
||||
fontSize: 12,
|
||||
}}>重置</button>
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => setOpen(true)}
|
||||
style={{
|
||||
background: '#1A1A1A',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: 999,
|
||||
padding: '10px 16px',
|
||||
fontSize: 12,
|
||||
cursor: 'pointer',
|
||||
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
|
||||
}}
|
||||
>⚙ Tweaks</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 应用Tweaks
|
||||
|
||||
在主组件里用Tweaks:
|
||||
|
||||
```jsx
|
||||
function App() {
|
||||
const { tweaks } = useTweaks();
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
'--primary': tweaks.primaryColor,
|
||||
'--font-size': `${tweaks.fontSize}px`,
|
||||
background: tweaks.dark ? '#0A0A0A' : '#FAFAFA',
|
||||
color: tweaks.dark ? '#FAFAFA' : '#1A1A1A',
|
||||
}}>
|
||||
{/* 你的内容 */}
|
||||
<TweaksPanel />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
CSS里用变量:
|
||||
|
||||
```css
|
||||
button.cta {
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
font-size: var(--font-size);
|
||||
}
|
||||
```
|
||||
|
||||
## 典型 Tweak 选项
|
||||
|
||||
给不同类型的设计加什么tweaks:
|
||||
|
||||
### 通用
|
||||
- 主色(color picker)
|
||||
- 字号(slider 12-24px)
|
||||
- 字型(select:display font vs body font)
|
||||
- 暗黑模式(toggle)
|
||||
|
||||
### 幻灯片deck
|
||||
- 主题(light/dark/brand)
|
||||
- 背景样式(solid/gradient/image)
|
||||
- 字体对比(更装饰 vs 更克制)
|
||||
- 信息密度(minimal/standard/dense)
|
||||
|
||||
### 产品原型
|
||||
- 布局变体(layout A / B / C)
|
||||
- 交互速度(animation speed 0.5x-2x)
|
||||
- 数据量(mock数据条数 5/20/100)
|
||||
- 状态(empty/loading/success/error)
|
||||
|
||||
### 动画
|
||||
- 速度(0.5x-2x)
|
||||
- 循环(once/loop/ping-pong)
|
||||
- Easing(linear/easeOut/spring)
|
||||
|
||||
### Landing page
|
||||
- Hero风格(image/gradient/pattern/solid)
|
||||
- CTA文案(几种变体)
|
||||
- 结构(single column / two column / sidebar)
|
||||
|
||||
## Tweaks设计原则
|
||||
|
||||
### 1. 有意义的选项,不是折腾人的
|
||||
|
||||
每个tweak必须展示**真实的设计选项**。别加那种谁都不会真切换的tweak(比如border-radius 0-50px的slider——用户调完发现所有中间值都丑)。
|
||||
|
||||
好的tweak暴露**离散的、有思考的variations**:
|
||||
- "圆角风格":无圆角 / 微圆角 / 大圆角(三个选项)
|
||||
- 不是:"圆角":0-50px slider
|
||||
|
||||
### 2. 少即是多
|
||||
|
||||
一个设计的Tweaks面板**最多5-6个**选项。再多就变成"配置页面",失去了快速探索variations的意义。
|
||||
|
||||
### 3. 默认值是完成设计
|
||||
|
||||
Tweaks是**锦上添花**。默认值必须本身就是一个完整、可发布的设计。用户关闭Tweaks面板后看到的就是产出。
|
||||
|
||||
### 4. 合理分组
|
||||
|
||||
选项多时分组显示:
|
||||
|
||||
```
|
||||
---- 视觉 ----
|
||||
主色 | 字号 | 暗黑模式
|
||||
|
||||
---- 布局 ----
|
||||
密度 | 侧栏位置
|
||||
|
||||
---- 内容 ----
|
||||
显示数据量 | 状态
|
||||
```
|
||||
|
||||
## 向前兼容源码级持久化 host
|
||||
|
||||
如果你以后想把设计上传到支持源码级 tweaks(如 Claude.ai Artifacts)的环境也能跑,保留 **EDITMODE 标记块**:
|
||||
|
||||
```jsx
|
||||
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
|
||||
"primaryColor": "#D97757",
|
||||
"fontSize": 16,
|
||||
"density": "comfortable",
|
||||
"dark": false
|
||||
}/*EDITMODE-END*/;
|
||||
```
|
||||
|
||||
标记块在 localStorage 方案里**无作用**(只是个普通注释),但在支持源码回写的 host 里会被读取,实现源码级持久化。加上这个对当前环境无害,同时保持向前兼容。
|
||||
|
||||
## 常见问题
|
||||
|
||||
**Tweaks面板挡住设计内容**
|
||||
→ 让它可关闭。默认关闭,显示一个小按钮,用户点了才展开。
|
||||
|
||||
**用户切换tweaks后还要重复设置**
|
||||
→ 已经用localStorage。如果刷新后不持久,检查localStorage是否可用(无痕模式会失败,要catch)。
|
||||
|
||||
**多个HTML页面想共享tweaks**
|
||||
→ 给localStorage key加project name:`design-tweaks-[projectName]`。
|
||||
|
||||
**我想让tweak之间有联动关系**
|
||||
→ 在`update`里加逻辑:
|
||||
|
||||
```jsx
|
||||
const update = (patch) => {
|
||||
let next = { ...tweaks, ...patch };
|
||||
// 联动:选dark mode时自动切换字体配色
|
||||
if (patch.dark === true && !patch.textColor) {
|
||||
next.textColor = '#F0EEE6';
|
||||
}
|
||||
setTweaks(next);
|
||||
localStorage.setItem(...);
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,183 @@
|
||||
# Verification:输出验证流程
|
||||
|
||||
一些 design-agent 原生环境(如 Claude.ai Artifacts)有内置的 `fork_verifier_agent` 起 subagent 用 iframe 截图检查。大部分 agent 环境(Claude Code / Codex / Cursor / Trae / 等)里没有这个内置能力——用 Playwright 手动做就能覆盖相同的验证场景。
|
||||
|
||||
## 验证清单
|
||||
|
||||
每次产出HTML后,按这个清单做一遍:
|
||||
|
||||
### 1. 浏览器渲染检查(必做)
|
||||
|
||||
最基础:**HTML能不能打开**?在macOS上:
|
||||
|
||||
```bash
|
||||
open -a "Google Chrome" "/path/to/your/design.html"
|
||||
```
|
||||
|
||||
或者用Playwright截图(下一节)。
|
||||
|
||||
### 2. 控制台错误检查
|
||||
|
||||
HTML文件里最常见的问题是JS报错导致白屏。用Playwright跑一遍:
|
||||
|
||||
```bash
|
||||
python "$SKILL/scripts/verify.py" path/to/design.html
|
||||
```
|
||||
|
||||
这个脚本会:
|
||||
1. 用headless chromium打开HTML
|
||||
2. 截图保存到项目目录
|
||||
3. 抓取控制台错误
|
||||
4. 报告status
|
||||
|
||||
详见`scripts/verify.py`。
|
||||
|
||||
### 3. 多视口检查
|
||||
|
||||
如果是响应式设计,抓多个viewport:
|
||||
|
||||
```bash
|
||||
python verify.py design.html --viewports 1920x1080,1440x900,768x1024,375x667
|
||||
```
|
||||
|
||||
### 4. 交互检查
|
||||
|
||||
Tweaks、动画、按钮切换——默认的静态截图看不到。**建议让用户自己开浏览器点一遍**,或者用Playwright录屏:
|
||||
|
||||
```python
|
||||
page.video.record('interaction.mp4')
|
||||
```
|
||||
|
||||
### 5. 幻灯片逐页检查
|
||||
|
||||
Deck类HTML,一张张截:
|
||||
|
||||
```bash
|
||||
python verify.py deck.html --slides 10 # 截前10张
|
||||
```
|
||||
|
||||
生成 `deck-slide-01.png`、`deck-slide-02.png`... 方便快速浏览。
|
||||
|
||||
## Playwright Setup
|
||||
|
||||
首次使用需要:
|
||||
|
||||
```bash
|
||||
# 如果还没装
|
||||
npm install -g playwright
|
||||
npx playwright install chromium
|
||||
|
||||
# 或者Python版
|
||||
pip install playwright
|
||||
playwright install chromium
|
||||
```
|
||||
|
||||
如果用户已经全局安装 Playwright,直接用即可。
|
||||
|
||||
## 截图最佳实践
|
||||
|
||||
### 截完整页面
|
||||
|
||||
```python
|
||||
page.screenshot(path='full.png', full_page=True)
|
||||
```
|
||||
|
||||
### 截viewport
|
||||
|
||||
```python
|
||||
page.screenshot(path='viewport.png') # 默认只截可见区域
|
||||
```
|
||||
|
||||
### 截特定元素
|
||||
|
||||
```python
|
||||
element = page.query_selector('.hero-section')
|
||||
element.screenshot(path='hero.png')
|
||||
```
|
||||
|
||||
### 高清截图
|
||||
|
||||
```python
|
||||
page = browser.new_page(device_scale_factor=2) # retina
|
||||
```
|
||||
|
||||
### 等动画结束再截
|
||||
|
||||
```python
|
||||
page.wait_for_timeout(2000) # 等2秒让动画settle
|
||||
page.screenshot(...)
|
||||
```
|
||||
|
||||
## 把截图发给用户
|
||||
|
||||
### 本地截图直接打开
|
||||
|
||||
```bash
|
||||
open screenshot.png
|
||||
```
|
||||
|
||||
用户会在自己的 Preview/Figma/VSCode/浏览器 里看。
|
||||
|
||||
### 上传图床分享链接
|
||||
|
||||
如果需要给远程协作者看(比如 Slack/飞书/微信),让用户用自己的图床工具或 MCP 上传。任何返回永久链接的图床都行(ImgBB / Cloudflare R2 / 七牛 / 自建等),粘贴到任何地方。
|
||||
|
||||
## 验证出错时
|
||||
|
||||
### 页面白屏
|
||||
|
||||
控制台一定有错。先检查:
|
||||
|
||||
1. React+Babel script tag的integrity hash对不对(见`react-setup.md`)
|
||||
2. 是不是`const styles = {...}`命名冲突
|
||||
3. 跨文件的组件有没有export到`window`
|
||||
4. JSX语法错误(babel.min.js不报错,换babel.js非压缩版)
|
||||
|
||||
### 动画卡
|
||||
|
||||
- 用Chrome DevTools Performance tab录一段
|
||||
- 找layout thrashing(频繁的reflow)
|
||||
- 动效优先用`transform`和`opacity`(GPU加速)
|
||||
|
||||
### 字体不对
|
||||
|
||||
- 检查`@font-face`的url是否可访问
|
||||
- 检查fallback字体
|
||||
- 中文字体加载慢:先显示fallback,加载完再切换
|
||||
|
||||
### 布局错位
|
||||
|
||||
- 检查`box-sizing: border-box`是否全局应用
|
||||
- 检查`* margin: 0; padding: 0`reset
|
||||
- Chrome DevTools里打开gridlines看实际布局
|
||||
|
||||
## 验证=设计师的第二双眼
|
||||
|
||||
**永远要自己过一遍**。AI写代码时经常出现:
|
||||
|
||||
- 看起来对但interaction有bug
|
||||
- 静态截图好但scroll时错位
|
||||
- 宽屏好看但窄屏崩
|
||||
- Dark mode忘了测
|
||||
- Tweaks切换后某些组件没响应
|
||||
|
||||
**最后1分钟的验证可以省1小时的返工**。
|
||||
|
||||
## 常用验证脚本命令
|
||||
|
||||
```bash
|
||||
# 基础:打开+截图+抓错
|
||||
python verify.py design.html
|
||||
|
||||
# 多viewport
|
||||
python verify.py design.html --viewports 1920x1080,375x667
|
||||
|
||||
# 多slide
|
||||
python verify.py deck.html --slides 10
|
||||
|
||||
# 输出到指定目录
|
||||
python verify.py design.html --output ./screenshots/
|
||||
|
||||
# headless=false,打开真实浏览器给你看
|
||||
python verify.py design.html --show
|
||||
```
|
||||
@@ -0,0 +1,197 @@
|
||||
# Video Export:HTML 动画导出为 MP4/GIF
|
||||
|
||||
动画 HTML 完成后,用户常想「能导出视频吗」。这份指南给出完整流程。
|
||||
|
||||
## 何时导出
|
||||
|
||||
**导出时机**:
|
||||
- 动画完整跑通、视觉验证过(Playwright 截图确认各时间点状态正确)
|
||||
- 用户在浏览器里看过至少一次,表示效果 OK
|
||||
- **不要**在动画 bug 没修完的阶段导出——导出到视频后改起来更贵
|
||||
|
||||
**用户可能说的触发语**:
|
||||
- 「能导出成视频吗」
|
||||
- 「转成 MP4」
|
||||
- 「做成 GIF」
|
||||
- 「60fps」
|
||||
|
||||
## 产出规格
|
||||
|
||||
默认一次给三种格式,让用户选:
|
||||
|
||||
| 格式 | 规格 | 适合场景 | 典型大小(30s) |
|
||||
|---|---|---|---|
|
||||
| MP4 25fps | 1920×1080 · H.264 · CRF 18 | 公众号嵌入、视频号、YouTube | 1-2 MB |
|
||||
| MP4 60fps | 1920×1080 · minterpolate 插帧 · H.264 · CRF 18 | 高帧率展示、B站、作品集 | 1.5-3 MB |
|
||||
| GIF | 960×540 · 15fps · palette 优化 | Twitter/X、README、Slack 预览 | 2-4 MB |
|
||||
|
||||
## 工具链
|
||||
|
||||
两个脚本在 `scripts/`:
|
||||
|
||||
### 1. `render-video.js` — HTML → MP4
|
||||
|
||||
录一个 25fps 的 MP4 基础版本。依赖全局 playwright。
|
||||
|
||||
```bash
|
||||
NODE_PATH=$(npm root -g) node /path/to/claude-design/scripts/render-video.js <html文件>
|
||||
```
|
||||
|
||||
可选参数:
|
||||
- `--duration=30` 动画时长(秒)
|
||||
- `--width=1920 --height=1080` 分辨率
|
||||
- `--trim=2.2` 从视频开头裁掉的秒数(去掉 reload + 字体加载时间)
|
||||
- `--fontwait=1.5` 字体加载等待时间(秒),字体多时调高
|
||||
|
||||
输出:与 HTML 同目录,同名 `.mp4`。
|
||||
|
||||
### 2. `add-music.sh` — MP4 + BGM → MP4
|
||||
|
||||
给无声 MP4 混入背景音乐,按场景(mood)从内置 BGM 库里选,也可自带音频。自动匹配时长、加淡入淡出。
|
||||
|
||||
```bash
|
||||
bash add-music.sh <input.mp4> [--mood=<name>] [--music=<path>] [--out=<path>]
|
||||
```
|
||||
|
||||
**内置 BGM 库**(在 `assets/bgm-<mood>.mp3`):
|
||||
|
||||
| `--mood=` | 风格 | 适配场景 |
|
||||
|-----------|------|---------|
|
||||
| `tech`(默认) | Apple Silicon / 苹果发布会,极简合成器+钢琴 | 产品发布、AI工具、Skill 宣传 |
|
||||
| `ad` | upbeat 现代电子,有 build + drop | 社交媒体广告、产品预告、促销片 |
|
||||
| `educational` | 温暖明亮、轻吉他/电钢琴,inviting | 科普、教程介绍、课程预告 |
|
||||
| `educational-alt` | 同类备选,换一首试试 | 同上 |
|
||||
| `tutorial` | lo-fi 环境音,几乎无存在感 | 软件演示、编程教程、长演示 |
|
||||
| `tutorial-alt` | 同类备选 | 同上 |
|
||||
|
||||
**行为**:
|
||||
- 音乐按视频时长裁剪
|
||||
- 0.3s 淡入 + 1s 淡出(避免硬切)
|
||||
- 视频流 `-c:v copy` 不重编码,音频 AAC 192k
|
||||
- `--music=<path>` 优先级高于 `--mood`,可以直接指定任意外部音频
|
||||
- 传错 mood 名会列出所有可用选项,不会静默失败
|
||||
|
||||
**典型流水线**(动画导出三件套 + 配乐):
|
||||
```bash
|
||||
node render-video.js animation.html # 录屏
|
||||
bash convert-formats.sh animation.mp4 # 派生 60fps + GIF
|
||||
bash add-music.sh animation-60fps.mp4 # 加默认 tech BGM
|
||||
# 或针对不同场景:
|
||||
bash add-music.sh tutorial-demo.mp4 --mood=tutorial
|
||||
bash add-music.sh product-promo.mp4 --mood=ad --out=promo-final.mp4
|
||||
```
|
||||
|
||||
### 3. `convert-formats.sh` — MP4 → 60fps MP4 + GIF
|
||||
|
||||
从已有 MP4 生成 60fps 版本和 GIF。
|
||||
|
||||
```bash
|
||||
bash /path/to/claude-design/scripts/convert-formats.sh <input.mp4> [gif_width]
|
||||
```
|
||||
|
||||
输出(与输入同目录):
|
||||
- `<name>-60fps.mp4` — minterpolate 插帧到 60fps
|
||||
- `<name>.gif` — palette 优化的 GIF(默认 960 宽,可改)
|
||||
|
||||
`gif_width` 参数:
|
||||
- 960(默认)—— 社交平台通用
|
||||
- 1280 —— 更清晰但文件更大
|
||||
- 600 —— Twitter/X 优先加载
|
||||
|
||||
## 完整流程(标准推荐)
|
||||
|
||||
用户说「导出视频」后:
|
||||
|
||||
```bash
|
||||
cd <项目目录>
|
||||
|
||||
# 假设 $SKILL 指向本 skill 的根目录(自行按安装位置替换)
|
||||
|
||||
# 1. 录 25fps 基础 MP4
|
||||
NODE_PATH=$(npm root -g) node "$SKILL/scripts/render-video.js" my-animation.html
|
||||
|
||||
# 2. 派生 60fps MP4 和 GIF
|
||||
bash "$SKILL/scripts/convert-formats.sh" my-animation.mp4
|
||||
|
||||
# 产出清单:
|
||||
# my-animation.mp4 (25fps · 1-2 MB)
|
||||
# my-animation-60fps.mp4 (60fps · 1.5-3 MB)
|
||||
# my-animation.gif (15fps · 2-4 MB)
|
||||
```
|
||||
|
||||
## 技术细节(排错用)
|
||||
|
||||
### Playwright recordVideo 的坑
|
||||
|
||||
- 帧率固定 25fps,无法直接录 60fps(Chromium headless 的 compositor 上限)
|
||||
- 从 context 创建就开始录,必须用 `trim` 裁掉前面的加载时间
|
||||
- 默认 webm 格式,需要 ffmpeg 转 H.264 MP4 才能通用播放
|
||||
|
||||
`render-video.js` 已处理以上问题。
|
||||
|
||||
### ffmpeg minterpolate 参数
|
||||
|
||||
当前配置:`minterpolate=fps=60:mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1`
|
||||
|
||||
- `mi_mode=mci` — motion compensation interpolation(运动补偿)
|
||||
- `mc_mode=aobmc` — adaptive overlapped block motion compensation
|
||||
- `me_mode=bidir` — 双向运动估计
|
||||
- `vsbmc=1` — 可变 size block motion compensation
|
||||
|
||||
对 CSS **transform 动画**(translate/scale/rotate)效果好。
|
||||
对**纯 fade** 可能产生轻微 ghosting——如果用户嫌弃,退化为简单帧复制:
|
||||
|
||||
```bash
|
||||
ffmpeg -i input.mp4 -r 60 -c:v libx264 ... output.mp4
|
||||
```
|
||||
|
||||
### GIF palette 为何要两阶段
|
||||
|
||||
GIF 只能 256 色。一次 pass 的 GIF 会把全动画色彩压到 256 色通用 palette,对米色底+橙色这种细腻配色会糊。
|
||||
|
||||
两阶段:
|
||||
1. `palettegen=stats_mode=diff` —— 先扫描全片,生成**针对此动画的 optimal palette**
|
||||
2. `paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle` —— 用这个 palette 编码,rectangle diff 只更新变化区域,大幅减小文件
|
||||
|
||||
对 fade 过渡用 `dither=bayer` 比 `none` 更平滑,但文件大一点。
|
||||
|
||||
## Pre-flight check(导出前)
|
||||
|
||||
导出前 30 秒自检:
|
||||
|
||||
- [ ] HTML 在浏览器里完整跑过一遍,无控制台错误
|
||||
- [ ] 动画第 0 帧是完整初始状态(不是空白加载中)
|
||||
- [ ] 动画最后一帧是稳定的收尾状态(不是半截)
|
||||
- [ ] 字体/图片/emoji 全部正常渲染(参考 `animation-pitfalls.md`)
|
||||
- [ ] Duration 参数与 HTML 里的实际动画时长匹配
|
||||
|
||||
## 交付时附带的说明
|
||||
|
||||
导出完成后给用户的标准说明格式:
|
||||
|
||||
```
|
||||
**完整交付**
|
||||
|
||||
| 文件 | 格式 | 规格 | 大小 |
|
||||
|---|---|---|---|
|
||||
| foo.mp4 | MP4 | 1920×1080 · 25fps · H.264 | X MB |
|
||||
| foo-60fps.mp4 | MP4 | 1920×1080 · 60fps(运动插帧)· H.264 | X MB |
|
||||
| foo.gif | GIF | 960×540 · 15fps · palette 优化 | X MB |
|
||||
|
||||
**说明**
|
||||
- 60fps 用 minterpolate 做运动估计插帧,transform 动画效果好
|
||||
- GIF 用 palette 优化,30s 动画可压到 3MB 左右
|
||||
|
||||
要换尺寸或帧率说一声。
|
||||
```
|
||||
|
||||
## 常见用户追加需求
|
||||
|
||||
| 用户说 | 应对 |
|
||||
|---|---|
|
||||
| 「太大了」 | MP4:提高 CRF 到 23-28;GIF:降分辨率到 600 或 fps 到 10 |
|
||||
| 「GIF 太糊」 | 提高 `gif_width` 到 1280;或者建议用 MP4 代替(微信朋友圈也支持) |
|
||||
| 「要竖屏 9:16」 | 改 HTML 源的 `--width=1080 --height=1920`,重新录 |
|
||||
| 「加水印」 | ffmpeg 加 `-vf "drawtext=..."` 或 `overlay=` 一个 PNG |
|
||||
| 「要透明背景」 | MP4 不支持 alpha;用 WebM VP9 + alpha 或 APNG |
|
||||
| 「要无损」 | CRF 改 0 + preset veryslow(文件会大 10 倍) |
|
||||
@@ -0,0 +1,216 @@
|
||||
# Workflow:从接到任务到交付
|
||||
|
||||
你是用户的junior designer。用户是manager。按这个流程工作,能产出好设计的概率会显著提升。
|
||||
|
||||
## 问问题的艺术
|
||||
|
||||
大多数情况下,开工前要问至少10个问题。不是走过场,是真的要把需求摸清。
|
||||
|
||||
**什么时候必须问**:新任务、模糊任务、没有design context、用户只说了一句模糊的要求。
|
||||
|
||||
**什么时候可以不问**:小修小补、follow-up任务、用户已经给了明确PRD+截图+上下文。
|
||||
|
||||
**怎么问**:大部分 agent 环境没有结构化问题 UI,在对话里用 markdown 清单问即可。**一次性把问题列完让用户批量答**,不要一来一回一个个问——那会浪费用户时间、打断用户思路。
|
||||
|
||||
## 必问清单
|
||||
|
||||
每个设计任务都必须问清这5类问题:
|
||||
|
||||
### 1. Design Context(最重要)
|
||||
|
||||
- 有没有现成的design system、UI kit、组件库?在哪?
|
||||
- 有没有品牌指南、色彩规范、字体规范?
|
||||
- 有没有可以参考的现有产品/页面截图?
|
||||
- 有没有codebase可以读?
|
||||
|
||||
**如果用户说"没有"**:
|
||||
- 帮他找——翻项目目录、看有没有参考品牌
|
||||
- 还没有?明确说:"我会基于通用直觉做,但这通常做不出符合你品牌的作品。你考虑下是否先提供一些参考?"
|
||||
- 实在要做,就按`references/design-context.md`的fallback策略办
|
||||
|
||||
### 2. Variations维度
|
||||
|
||||
- 想要几种variations?(推荐3+)
|
||||
- 在哪些维度上变?视觉/交互/色彩/布局/文案/动画?
|
||||
- 希望variations都"接近预期"还是"一张地图,从保守到疯狂"?
|
||||
|
||||
### 3. Fidelity和Scope
|
||||
|
||||
- 多高保真?线框图 / 半成品 / 真实data的full hi-fi?
|
||||
- 覆盖多少flow?一屏 / 一个flow / 整个产品?
|
||||
- 有没有具体的「必须包含」元素?
|
||||
|
||||
### 4. Tweaks
|
||||
|
||||
- 希望能实时调整哪些参数?(颜色/字号/间距/layout/文案/feature flag)
|
||||
- 用户自己要不要在做完后继续调?
|
||||
|
||||
### 5. 问题专属(至少4个)
|
||||
|
||||
针对具体任务问4+个细节。例如:
|
||||
|
||||
**做landing page**:
|
||||
- 目标转化动作是什么?
|
||||
- 主要受众?
|
||||
- 竞品参考?
|
||||
- 文案谁提供?
|
||||
|
||||
**做iOS App onboarding**:
|
||||
- 几步?
|
||||
- 需要用户做什么?
|
||||
- 跳过路径?
|
||||
- 目标留存率?
|
||||
|
||||
**做动画**:
|
||||
- 时长?
|
||||
- 最终用途(视频素材/官网/社交)?
|
||||
- 节奏(快/慢/分段)?
|
||||
- 必须出现的关键帧?
|
||||
|
||||
## 问题模板示例
|
||||
|
||||
遇到新任务时,可以抄这个结构在对话里问:
|
||||
|
||||
```markdown
|
||||
开始前想跟你对齐几个问题,一次列齐你批量回答就行:
|
||||
|
||||
**Design Context**
|
||||
1. 有设计系统/UI kit/品牌规范吗?如果有在哪?
|
||||
2. 有可以参考的现有产品或竞品截图吗?
|
||||
3. 项目里有codebase可以读吗?
|
||||
|
||||
**Variations**
|
||||
4. 想要几种variations?在哪些维度上变(视觉/交互/色彩/...)?
|
||||
5. 希望都是"接近答案"还是从保守到疯狂的一张地图?
|
||||
|
||||
**Fidelity**
|
||||
6. 保真度:线框 / 半成品 / 带真数据full hi-fi?
|
||||
7. Scope:一屏 / 一整个flow / 整个产品?
|
||||
|
||||
**Tweaks**
|
||||
8. 希望做完后能实时调哪些参数?
|
||||
|
||||
**具体任务**
|
||||
9. [任务专属问题1]
|
||||
10. [任务专属问题2]
|
||||
...
|
||||
```
|
||||
|
||||
## Junior Designer模式
|
||||
|
||||
这是整个workflow最重要的环节。**不要接到任务就闷头冲**。步骤:
|
||||
|
||||
### Pass 1:Assumptions + Placeholders(5-15分钟)
|
||||
|
||||
HTML文件头部先写你的**assumptions+reasoning comments**,像junior给manager汇报:
|
||||
|
||||
```html
|
||||
<!--
|
||||
我的假设:
|
||||
- 这是给XX受众看的
|
||||
- 整体tone我理解为XX(基于用户说的"专业但不严肃")
|
||||
- 主要flow是A→B→C
|
||||
- 色彩我想用品牌蓝+暖灰,不确定你想不想要accent色
|
||||
|
||||
未解的问题:
|
||||
- 第3步的数据从哪里来?先用placeholder
|
||||
- 背景图用抽象几何还是真照片?先占位
|
||||
|
||||
如果你看到这里觉得方向不对,现在是成本最低的时候改。
|
||||
-->
|
||||
|
||||
<!-- 然后是带placeholder的结构 -->
|
||||
<section class="hero">
|
||||
<h1>[主标题位 - 等用户提供]</h1>
|
||||
<p>[副标题位]</p>
|
||||
<div class="cta-placeholder">[CTA按钮]</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
**保存 → show用户 → 等反馈再走下一步**。
|
||||
|
||||
### Pass 2:真实组件+Variations(主力工作量)
|
||||
|
||||
用户批准方向后,开始填充。这时:
|
||||
- 写React组件替换placeholder
|
||||
- 做variations(用design_canvas或Tweaks)
|
||||
- 如果是幻灯片/动画,用starter components起手
|
||||
|
||||
**做到一半再show一次**——不要等全做完。设计方向错了,晚show等于白做。
|
||||
|
||||
### Pass 3:细节打磨
|
||||
|
||||
用户满意整体后,打磨:
|
||||
- 字号/间距/对比度微调
|
||||
- 动画timing
|
||||
- 边界case
|
||||
- Tweaks面板完善
|
||||
|
||||
### Pass 4:验证+交付
|
||||
|
||||
- 用Playwright截图(见`references/verification.md`)
|
||||
- 打开浏览器肉眼确认
|
||||
- 总结**极简**:只说caveats和next steps
|
||||
|
||||
## Variations的深度逻辑
|
||||
|
||||
给variations不是给用户制造选择困难,是**探索可能性空间**。让用户mix and match出最终版本。
|
||||
|
||||
### 好的variations长什么样
|
||||
|
||||
- **维度明确**:每个variation在不同维度上变(A vs B只换配色,C vs D只换layout)
|
||||
- **有梯度**:从「by-the-book保守版」到「大胆novel版」逐级递进
|
||||
- **有记号**:每个variation有短label说明它在探索什么
|
||||
|
||||
### 实现方式
|
||||
|
||||
**纯视觉对比**(静态):
|
||||
→ 用`assets/design_canvas.jsx`,网格布局并排展示。每个cell带label。
|
||||
|
||||
**多选项/交互差异**:
|
||||
→ 做完整原型,用Tweaks切换。例如做登录页,"布局"是tweak的一个选项:
|
||||
- 左文案右表单
|
||||
- 顶部logo+中央表单
|
||||
- 背景全屏图+浮层表单
|
||||
|
||||
用户开关Tweaks就能切换,不需要打开多个HTML文件。
|
||||
|
||||
### 探索矩阵思考
|
||||
|
||||
每次设计,脑内过一遍这些维度,挑2-3个来给variations:
|
||||
|
||||
- 视觉:minimal / editorial / brutalist / organic / futuristic / retro
|
||||
- 色彩:monochrome / dual-tone / vibrant / pastel / high-contrast
|
||||
- 字型:sans-only / sans+serif对比 / 全衬线 / 等宽
|
||||
- Layout:对称 / 非对称 / 不规则grid / full-bleed / 窄栏
|
||||
- Density:稀疏呼吸 / 中等 / 信息密集
|
||||
- 交互:极简hover / 丰富micro-interaction / 夸张大动画
|
||||
- 材质:flat / 有阴影层次 / 纹理 / noise / 渐变
|
||||
|
||||
## 遇到不确定的情况
|
||||
|
||||
- **不知道怎么做**:坦白说你不确定,问用户,或先做个placeholder继续。**不要编**。
|
||||
- **用户的描述矛盾**:指出矛盾,让用户选一个方向。
|
||||
- **任务太大一次吃不下**:拆成steps,先做第一步让用户看,再推进。
|
||||
- **用户要求的效果技术上很难**:说清技术边界,提供替代方案。
|
||||
|
||||
## 总结规则
|
||||
|
||||
交付时,summary **极短**:
|
||||
|
||||
```markdown
|
||||
✅ 幻灯片已完成(10张),带Tweaks可切换"夜/日模式"。
|
||||
|
||||
注意:
|
||||
- 第4页的数据是假的,等你提供真数据我替换
|
||||
- 动画用了CSS transition,不需要JS
|
||||
|
||||
下一步建议:先你浏览器打开看一遍,有问题告诉我哪页哪处。
|
||||
```
|
||||
|
||||
不要:
|
||||
- 罗列每一页的内容
|
||||
- 重复讲你用了什么技术
|
||||
- 夸自己设计多好
|
||||
|
||||
Caveats + next steps,结束。
|
||||
Reference in new issue
Block a user