Back to skills
SKILL.md
Penwash
ASecurity「钢笔淡彩」——用 Python 手搓钢笔线稿 + 水彩淡彩的静物/小景(细钢笔线抖着走、暗部排线、几块水彩故意不贴线、米色纸留白)。不是滤镜、不是生图。触发词:钢笔淡彩、淡彩、钢笔水彩、pen and wash、排线、画成那种线稿上色的、手绘静物
- 2 stars
- 0 votes
- 0 copies
- 1 view
- Added September 22, 2026
Security analysis
92/100- Installs packages at runtime which could introduce malicious dependencies
Pro scans all 5 files and shows the line behind each finding
npx -y skills add Qizhan7/pencil-case --skill penwash --agent claude-codeAre you the author of Penwash?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/qizhan7-penwash)---
name: penwash
description: 「钢笔淡彩」——用 Python 手搓钢笔线稿 + 水彩淡彩的静物/小景(细钢笔线抖着走、暗部排线、几块水彩故意不贴线、米色纸留白)。不是滤镜、不是生图。触发词:钢笔淡彩、淡彩、钢笔水彩、pen and wash、排线、画成那种线稿上色的、手绘静物
---
# 钢笔淡彩 —— 线 + 透明水,Python 一段一段画出来的
不是滤镜,不是生图。米色纸上,细钢笔线抖着走,暗部排线,几块水彩故意不贴线,大片留白。
适合静物、小景、一件东西的「肖像」。一张 900×1100 通常 2–15 秒。
依赖:`pip install pillow numpy`。中文手写感字体会自动找(macOS 娃娃体 → 苹方 → Noto → PIL 默认),想指定:`P.FONT = "/path/to/font.ttf"`。
**第一次用先跑 `python3 example.py`**:出来的图和包里的 `example.png` 一模一样(seed 固定),环境就对了。跑不出来只有三种原因:没装 pillow / numpy;`record.py` 录视频要系统里有 ffmpeg(只画图不需要);Linux 上中文显示成方块是缺中文字体,装个 Noto CJK 或指定 `P.FONT`。
## 先说最重要的一条:收到照片,不临摹,重新构思
照片是素材,不是构图。别人发一张照片说「画成这样」,不是让你把照片描一遍:
1. 先看这张照片真正是关于什么——一样东西、一个瞬间、一个人那天的重点。用一句话写下来。
2. 画面里只留这一句话需要的东西,**三样以内**,其余全部扔掉。照片里的桌角、插座、背景的楼、多出来的杯子——不要。
3. 构图自己定:视角、大小、位置、留白、什么贴边、什么只露一角。不跟照片的机位走。
4. **没有背景。** 这种画都是没背景的:物件直接落在纸上,最多一条断断续续的桌面线。照片里的墙、窗、楼、桌布——都不画。颜色只借色相,降饱和三成;透视可以歪,比例可以夸。
5. 参考图(别人的画)只借质感——线的抖法、排线密度、颜色出线多少——一根线都不借画面。
目标是「拍这张照片的人一眼认出是那天」,不是「和照片一样」。照着照片画一定会画规整、会把照片里所有东西都搬进来,出来的是插图,不是这个风格。真正好的一张往往是照片里没拍到的那样东西:对面空着的位子上那部亮着的手机,比桌上两杯酒更是那天。
## 风格标尺(先读这节再动手)
1. **线在说话,色不说话。** 纸干净(默认 `paper()`,别轻易 `vintage`),色块少而薄,线狠,留白大。色一多线就被泡软。
2. **线的抖跟物件尺寸走。** 物件放大 k 倍,`wobble`、`gaps`、椭圆 `rough` 同放 k 倍,线宽也跟着肥。高频 `jitter` 让线毛,不让线活;活是整条线大幅度的弯和不准。
3. **椭圆别画圆**(杯口 `rough≥0.04`),竖棱不等距,多边形手画着歪。用 catmull 平滑一次,折线就又变回「完美」——有棱的东西别平滑。
4. **留白是这个风格的一半。** 画区只占纸的六成,默认三样以内,不要塞。多件平铺(flat lay)是例外:每件缩小、留白靠件与件之间的空气。
5. **画还不存在的东西,比照着实物画更好。** 没有参考可抄,画面自动只剩线和留白,天然落在「不规整」上;有照片对着画反而会画规整、会把照片里所有东西搬进来。照片只用来认形状和颜色,画面里只留「那天的重点」。
6. **每张画写下三样东西各是哪件真事。没有真事不动手。** 静物画的是「那天」,不是「一个杯子」。
7. **署名竖写**在画右侧:一行主题 + 一行日期(`vertical_text`),角落一个字母(`pen_text`)。
## 引擎:`penwash_lib.py`
```python
import sys; sys.path.insert(0, "<这个目录>")
import penwash_lib as P
P.set_size(900, 1100)
img = P.paper(900, 1100) # 米色纸 + 噪 + 900 根纤维
```
| 函数 | 干什么 | 手感 |
|---|---|---|
| `paper(w,h,color,grain,fibers,vintage)` | 米色纸:细噪 + 短纤维。`vintage=True` 旧纸:更暖更深、低频斑驳、粗颗粒 | 默认就好;纸色 `PAPER=(243,236,221)`,旧纸 `(234,222,196)` |
| `pen_path(base, pts, ink, width, alpha, wobble, step, gaps, smooth, per, overdraw, jitter, overshoot, nib, shift)` | **钢笔线**:Catmull 平滑后每 `step` px 画一小段,线宽随平滑噪声起伏,`gaps` 概率断墨,`overdraw` 再淡淡描一遍(带随机 ±2px 偏移) | 主轮廓 `width=(1.0,2.0) alpha=(185,245) wobble=1.0 gaps=0.04 overdraw=1`;辅助线 `INK_SOFT width=(0.7,1.3) alpha=(110,180)`;直线段/折线传 `smooth=False` |
| `pen_ellipse / pen_arc` | 椭圆 / 弧(杯口、杯底、脚) | `rough=0.02–0.06` 让椭圆不完美 |
| `hatch(base, mask, angle, spacing, ink, width, alpha, length, density, cross)` | **排线**:mask 内铺平行短线,每条长度是可用长度的 `length` 比例、端点抖 | 深色实物 `angle=86 spacing=2.9 alpha=(140,220) density=0.97`;玻璃暗部 `spacing=3.6 alpha=(80,150) length=(0.35,0.85) density=0.75`;`cross=True` 交叉排线更黑 |
| `wash(base, polygon, color, alpha, offset, feather, layers, edge, texture)` | **淡彩**:多边形偏移 `offset` 再羽化、`layers` 层错位叠、`edge` 压一圈沉淀、`texture` 低频水痕 | 主色块 `alpha=(90,135) offset=(6,4) feather=3 layers=2 edge=0.45`;投影 `alpha=(30,60) feather=5–8 edge=0 texture=0.5`;留白孔 `color=P.PAPER alpha=(215,240) texture=0` |
| `wash_mask(base, mask, color, ...)` | 已有 L 蒙版直接上色 | |
| `speckle(base, polygon, color, n, r, alpha)` | 色块上撒小点(杯座那圈、泡沫) | |
| `vertical_text(base, text, xy, size, alpha, gap, rot)` | 竖写一列,逐字歪 | 主题 28px alpha 200;日期 22px alpha 160 |
| `pen_text(base, text, xy, size, ...)` | 横写小字 | 角落字母 30px;物件上的小注 15px `INK_SOFT alpha 170` |
| `blob / ellipse_pts / poly_mask / catmull` | 几何 | `blob(cx,cy,rx,ry,k,rough)` 身体/影子;`poly_mask(poly, feather, grow, shrink)` 给 hatch 用 |
## 参数手感
- **线要比你以为的重。** 全图线 alpha 150 / width 0.8 出来像铅笔描的,颜色反客为主;alpha 185–245 / width 1.0–2.0 才是钢笔。线是骨架,颜色是薄薄一层。
- **排线要密才读得出**:spacing ≤ 3.6,alpha ≥ 110。排线 alpha 40–90 等于没画。
- **淡彩三层错位 + edge 0.45–0.5** 才有水彩堆积感;`texture=0.45` 起才不像 PS 填充。
- **构图**:物件之间留 25px 以上空隙,别互相压。桌面静物的底部落在同一条桌面线上 ±10px,桌面线 `INK_SOFT gaps=0.14` 断断续续。
- **降饱和三成的色板**比原色好看:橙 `(206,148,104)`/浅 `(224,188,150)`,蓝 `(104,156,170)`/浅 `(168,196,204)`,咖啡 `(146,104,68)`/浅 `(206,168,124)`,奶 `(240,228,202)`,冰蓝 `(172,198,214)`,投影 `(186,194,200)`,墨 `INK=(58,44,36)` 淡墨 `(96,78,66)`。
- **手绘感四件套**(`pen_path` 参数,物件放大后尤其要):`nib=True` 起笔加重收笔提起;`overshoot=5–6` 折线角上出头;`overdraw` 第二遍不在原地;`jitter=0.35` 高频小抖让线「硬」。可以 `HAND = dict(jitter=0.35, nib=True)` 全局带上。
## 技法(按材质)
- **透明物(玻璃、冰)少上色**:只描框 + 一个角一小片淡蓝 `alpha=(70,100)` + 一条折线。内线一条就够,多了成乱线。
- **深色实物**(黑塑料、深瓶):`(70,60,62)` alpha 120–160 打底,再排线 spacing 2.9–3.1,最后轮廓 overdraw=1。孔用纸色 wash 留白再描圈。
- **金属 = 留白 + 一条深边**,不是灰:底 `(216,220,224) alpha 28–44`,暗部只在一侧一条,排线只排暗侧,亮面别撒短线(撒了像下雨)。镂空用 `P.PAPER alpha 225–245 texture 0` 留白再描洞边。
- **毛/刺**:放射短线 400–600 条,起点在半径 0.3–0.9,长度随半径变长,ink 在 INK/INK_SOFT 间随机;毛那侧不描轮廓,让毛尖当边。
- **软的东西**(布、叠好的衣服、袋子)别画成盒子:轮廓用 8 个控制点 catmull、每边中点外鼓 3–4px;褶皱是几条竖短线;带子只露两头。
- **有棱的东西**(手捏的团、切开的面)别平滑:手写十几个点,`smooth=False, overshoot=3, wobble=1.3` 画折线;凹陷 = 小椭圆暗 wash + 下半圈深线。
- **不透明液体前先盖底**:`wash(poly, P.PAPER, alpha=(225,245), feather=1.5, texture=0)` 把底下的图案遮掉,不然桌面纹路从液体里透出来。透明的部分故意不遮。
- **默认没有背景**。唯一的例外是那天的重点本身就是一片光(落日、窗):那就下重手,整块先铺一层暖 `(238,222,186) alpha 26–38`,再 halo(feather 24)→ 主体 → 核心 `alpha 175–215`,淡了就没有「把窗烧白」的感觉;除了这团光别的背景线一根不画。
- **重复图案是这个风格的甜点**(圆点桌面、雨点玻璃):透视排的 `pen_ellipse` 或直接撒点;**只围着主角**,按到主角的距离衰减 `p = 1-(d/R)²`,alpha 也随 p 降,远处自然散掉。
- **植物**:叶从茎往下垂、尖朝地;掉两片在地上;枯叶 `(160,152,100)` / `(198,176,112)`。
- **像素/格子**(拼豆、马赛克):先按格 wash 整块,再每格一个小孔 + 只描右、下两条格线,最后沿外沿走一圈折线。
- **多件平铺**:网格松散排、每件 100–160px、件间 ≥ 60px,留白靠件与件之间的空气。
- **几何小工具**:新月 = 大圆减偏移小圆(`example.py` 的 `crescent()`);链子 = 沿曲线按弧长每 15px 放一节、大小椭圆交替、顺切线;尖拱两条线在顶尖 `overshoot=5` 交叉出头。
- 细弧下面别摊一片影子(texture 出来像脏点),影子跟着弧走一条窄带。
- **旧纸 `paper(vintage=True)`**:颜色配套深一档,线宽配套加肥。
## 录制画画过程
引擎本来就是一笔一笔画的,`record.py` 把每次落笔喂给 ffmpeg 一帧(默认两笔一帧,wash / 撒点 / 每个字必出一帧,开头结尾各停一两秒):
```bash
python3 record.py example.py example.mp4 # 163 帧 5 秒,2 秒渲染完
python3 record.py my.py my.mp4 4 30 # 刺、排线多的画把 every 调大,不然一根根刺看半天
```
脚本一个字不用改。自己在脚本里打点:`P.record_start(path)` … `P.record_hold(img, 15)`(停一下)… `P.record_stop()`。需要系统里有 ffmpeg。
## 两个例子
包里的 `example.png` / `example_cats.png` 是给你看目标长什么样的,**不是拿来描的**。画新东西的时候构图重新想——上面「收到照片,不临摹」那一节对例图同样适用;照着例图的坐标改两个数换个杯子,出来的就是同一张画换了个壳。想看它一笔一笔画:`python3 record.py example_cats.py example_cats.mp4 4`。
- `example.py`:静物(马克杯、半颗柠檬、新月吊坠)——线 + 排线 + 淡彩全套。
- `example_cats.py`:潦草线条小猫,速写本一页五个姿势——线找形(`scr()` 每条线画 2–3 遍各偏几个像素、alpha 减半、wobble ×1.3)、不闭合、几乎不上色。想要「随手画的」感觉从这个起。
## 工作流
1. 写下三样东西各是哪件真事。**没有真事不动手。**
2. 拷 `example.py`(静物)或 `example_cats.py`(潦草线)改,别从空白起。坐标全写成变量(cx / jx / ccx),改构图只动那几个数。
3. 跑,看四样:线够不够重、排线看不看得见、三样有没有互相压、署名压没压到画。两版内。
4. 输出 `penwash-<主题>-<日期>.png`,脚本留同目录。
## 反馈怎么读
- 「再艺术一点」= 少、歪、色块、留白。照片不是构图。
- 「太规整」= 线的抖没跟上物件尺寸,或者 catmull 把本该有棱的折线磨圆了。
- 「太完美」有时是夸。改之前先问一句。
- 看画的人裁了一刀 = 按裁剪比例放大重画,物件大、贴边,静物特写比全景有感觉。
## 坑
- `wash` 默认 `texture=0.45`,画留白孔、鼻子、眼睛这种要实的传 `texture=0.0`。
- `hatch` 是一条线一条线调 `pen_path`,大面积(>200×300 且 spacing<3)要几秒,别把整张纸 hatch。
- `pen_path` 的 `pts` 少于 3 点时不做 Catmull,两点直线要显式 `smooth=False` 才不报错。
- 随机种子固定(`random.seed` + `np.random.seed` 都要设),改参数才能对比。
- 闭合 blob / 圆:`pen_path(blob + [blob[0]])` 直接就是圆(重采样余量跨段累积,输入点再密也不会退化成几根直线)。
- 一张 900×1200 带 400+ 圆点约 30–40 秒,别在循环里再套 overdraw。
Files in this skill
- SKILL.md
- example.py
- example_cats.py
- penwash_lib.py
- record.py
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.