原型手绘皮肤技能 是做什么的?
让一个真实运行的 Web 应用看起来像是手绘的,这样客户就能明白它仍是原型,而非最终产品。这仅是外观与感受的皮肤,纯附加且完全可逆。
范围护栏(请先阅读,切勿违反)
- 只触碰样式入口和
index.html。 追加一个样式表、粘贴一个 SVG 块、设置两个属性。除此之外不做任何事。 - 切勿编辑 组件、模板、
.ts/.tsx/.jsx/.vue逻辑、路由、状态、服务或测试。 - 切勿替换 组件为手绘组件库(如 wired-elements)——那会重写标记,禁止。
- 切勿重新着色或扭曲 必须保持清晰的 Logo、照片、图表或图标——请使用 opt-out 类。
- 回退必须简单:删除
<html>的两个属性即可关闭整个皮肤。
工作原理(一种思维模型)
- 一个样式表
assets/sketch-skin.css定义了全部 5 种样式及手绘度梯度。 - 一个 SVG 块
assets/sketch-filters.html定义了抖动滤镜(#sketch-25…#sketch-100)。 - 激活方式是在
<html>上设置两个属性:data-sketch="<style>"和data-sketch-level="<0|25|50|75|100>"。 - 外观来源于:手写字体替换 + 手绘边框(不规则圆角、平填充) + 一个SVG 位移滤镜,其强度即为手绘度。字体负责文本,滤镜只抖动边框装饰(绝不模糊文本)。
快速开始(请按顺序操作)
- 确认请求仅为皮肤。 如果用户需要行为/布局变更,立即停止——这超出范围。
- 识别框架,找到其全局样式表和
index.html(参见下方配置表)。 - 选择一种样式(见“样式”表格)和一个级别(
0、25、50、75或100)。 - 将皮肤 CSS 添加到项目的全局样式:
- 将
assets/sketch-skin.css复制到项目中(例如src/styles.scss)或使用@import导入。字体@import已包含在该文件中(在线使用)。
- 将
- 粘贴 SVG 滤镜:将
assets/sketch-filters.html的内容粘贴到index.html中紧随<body>开始标签之后的位置。(必须——filter: url(#sketch-…)只有在此定义存在于 DOM 中才能生效。) - 激活:编辑
index.html中的<html>标签:<html lang="en" data-sketch="balsamiq" data-sketch-level="50"> - 在浏览器中验证。要恢复,删除
data-sketch*两个属性(追加的 CSS/SVG 可以保持不动——没有属性它们不会产生任何效果)。
样式
data-sketch | 外观 | 字体 | 适用场景 |
|---|---|---|---|
balsamiq | 干净灰阶线框,扁平盒子 | Balsamiq Sans | 默认的“这是原型”效果 |
sharpie | 粗黑马克笔,重描边 | Permanent Marker | 白板/工作坊草图 |
pencil | 浅石墨色,柔和笔触 | Gaegu | 温和的“纸上铅笔”草稿 |
doodle | 俏皮,浅色点缀 | Short Stack | 友好、非正式的概念 |
blueprint | 蓝纸上的白墨水 | Patrick Hand | 技术“画板”感觉 |
手绘度级别
data-sketch-level 控制线条的抖动程度。它会选择不同的 SVG 位移滤镜:
| 级别 | 效果 |
|---|---|
0 | 手绘边框 + 字体,但线条直而稳定(最干净) |
25 | 轻微抖动 |
50 | 明显手绘(推荐默认值) |
75 | 松散、充满活力的草图 |
100 | 非常粗糙,最大程度的“涂鸦” |
如果设置了 data-sketch 但省略了 data-sketch-level,皮肤默认使用级别 50。
对角线水印(可选)
要将整个屏幕标记为草稿,可在 <html> 上添加第三个属性,包含要显示的文本:
<html data-sketch="balsamiq" data-sketch-level="50" data-sketch-watermark="草稿">
data-sketch-watermark 会在视口对角线上绘制一个淡淡的、手写体的单词。它是一个固定的、不可交互的图层(pointer-events: none),因此不会阻挡点击,不会改变布局,并且在页面和路由切换时保持不变。任何文本都可以(草稿、原型、机密、客户名称……)。删除该属性即可关闭。使用叠加层时,水印文本字段会实时设置它。
模态框、弹出框与 SPA 导航
由于皮肤通过 <html> 上的属性激活,并使用全局的 [data-sketch] … 选择器进行样式化,因此激活之后出现的任何内容都会自动继承——对话框、弹出层、下拉菜单、工具提示和 Toast(包括 Portal 挂载的)以及单页应用中的每个导航页面。无需逐个组件或逐个路由进行配置。
两点保持一致:
- 选择器列表已涵盖
dialog、[popover]、[role="dialog"]、[aria-modal="true"]、.modal、.popover、菜单、工具提示和 Toast,以及原生的::backdrop。 - 叠加层脚本会监视
<body>,如果框架在路由切换时替换了 body,它会重新注入 SVG 滤镜,从而确保抖动不会在无声中消失。(对于静态属性模型,将sketch-filters.html粘贴到<body>之后一次即可;SPA 框架会挂载到一个子根节点上,并保持其完整。)
框架注入配置
该皮肤与框架无关。以下是精确的目标位置;完整细节请参考 references/implementation.md。
| 栈 | CSS 添加位置 | SVG 粘贴位置 | 属性设置位置 |
|---|---|---|---|
| Angular | src/styles.scss(或 styles.css) | src/index.html 中 <body> 之后 | src/index.html 中的 <html> |
| React / Vite | src/index.css(在 main.tsx 中导入) | index.html 中 <body> 之后 | index.html 中的 <html> |
| Vue | src/assets/main.css(在 main.ts 中导入) | index.html 中 <body> 之后 | index.html 中的 <html> |
| 静态 HTML | 在 <head> 中链接 sketch-skin.css | index.html 中 <body> 之后 | index.html 中的 <html> |
保持特定资源清晰(opt-out)
皮肤不会编辑标记,但如果用户明确要求保护某个元素(Logo、图表),唯一允许的标记更改是向该单个元素添加 opt-out 钩子:
<img src="logo.svg" class="no-sketch" alt="Logo">
.no-sketch(或 data-no-sketch)会移除该元素的抖动滤镜和颜色覆盖。请谨慎使用,并仅在用户提出要求时使用。
交互式预览叠加层(可选)
当用户希望实时切换样式(例如向客户展示切换效果)时,请使用叠加层而非静态属性:
- 将
assets/sketch-skin.css添加到全局样式(同快速开始)。 - 在
</body>之前添加一个脚本标签:<script src="sketch-toggle.js" defer></script> - 完成。脚本会渲染一个浮动面板,包含关闭 + 每个主题的单选按钮、一个0-100% 手绘度滑块和一个水印文本字段,实时切换
<html>属性,并将选择保存在localStorage中。它会自动注入 SVG 滤镜(如果 SPA 替换了 body,还会重新注入),因此快速开始的第 5 步(粘贴sketch-filters.html)不再需要。
这仍然是仅皮肤、非破坏性的——脚本只是设置属性。删除标签即可禁用。当需求是“让我/客户切换样式”时选择此模型;对于固定、截图稳定的外观,请使用静态属性。
截图画廊
README.md 使用 demo/screenshots/ 中的 PNG 展示了每种样式及 0→100% 的梯度。这些图片是预先渲染的;生成它们的交互式演示应用和 Playwright 截图脚本位于项目的开发源码中,不会与安装的技能一起打包。技能本身仅包含 assets/ + references/ ——无需构建步骤,无依赖。
示例
示例 1 — Angular 演示,Balsamiq 风格,中等手绘
- 输入:“让这个 Angular 应用看起来像 Balsamiq 线框,用于明天的演示。”
- 操作:将
sketch-skin.css追加到src/styles.scss;将滤镜粘贴到src/index.html;设置<html data-sketch="balsamiq" data-sketch-level="50">。 - 结果:应用运行完全一样;渲染为灰阶线框。
示例 2 — React,最大锐利马克笔
- 输入:“React 应用,完全白板标记笔外观,非常粗糙。”
- 操作:在
main.tsx中导入sketch-skin.css;将滤镜粘贴到index.html;设置data-sketch="sharpie" data-sketch-level="100"。
示例 3 — 关闭皮肤
- 输入:“切换回真实的 UI。”
- 操作:从
<html>中删除data-sketch和data-sketch-level。完成——不需要其他更改。
故障排除
| 症状 | 原因 | 修复 |
|---|---|---|
| 盒子看起来手绘但线条完全笔直 | SVG 滤镜不在 DOM 中,或级别为 0 | 确认 sketch-filters.html 已粘贴到 <body> 之后;将级别设为 ≥ 25 |
| 完全没有变化 | 属性缺失或 CSS 未加载 | 验证 <html data-sketch="…"> 存在且 sketch-skin.css 在全局样式中 |
| 文本看起来模糊 | 滤镜应用于文本/整个 <body> | 不要将 filter: 添加到 body 或文本;皮肤仅过滤边框装饰——请重新复制未经修改的 sketch-skin.css |
| 字体不是手写体 | 离线/Google Fonts 被阻止 | 自托管字体——请参见 assets/fonts/README.md |
| 页面在大型表格/网格上感觉卡顿 | feDisplacementMap 对大型 DOM 的计算成本 | 降低级别,或缩小抖动选择器列表的范围(见 references/implementation.md) |
| Logo 变得去饱和/抖动 | 该资源未设置 opt-out | 向该单个元素添加 class="no-sketch" |
| 图标字体 / SVG 图标消失 | 过于激进的扁平化 | 向图标容器添加 no-sketch,或参见 references/implementation.md 中的图标注释 |
参考文件(仅在需要时阅读)
references/styles.md— 每种样式的精确字体/调色板/描边规范,以及如何添加新样式。references/implementation.md— SVG 滤镜数学、按框架的逐步指导、选择器调优、离线字体、性能、回退细节。