Design & media

栅格参考图转SVG规格

Try it

把一张栅格参考图(图标表、牌面表、UI 截图、设计稿切图)复刻成 SVG / Canvas 手绘图形时,用像素级测量代替目测:自动切分网格、按色系采样真色、连通域量出每个元素的位置尺寸并换算成 viewBox 坐标,最后生成「参考图 vs 本项目」并排对照页验证,再用结构计数断言(n 个点 = n 个圆)把结果钉死。当用户说「按这张图的图案改」「照着这个图做图标」「复刻这套牌面 / 表情 / 图标」「颜色不对,按参考图调」,或给出的参考图是低分辨率截图(有压缩噪点)时使用。

What it does

用户丢来一张图说「按这个改图案/图标」。肉眼估色估位**必偏**,而且低分辨率截图 (聊天软件压过的、缩放过的小图)会让「看着像」和「实际色值」差很远。全程用像素测量。

The skill document

栅格参考图 → SVG 规格

何时用

用户丢来一张图说「按这个改图案/图标」。肉眼估色估位必偏,而且低分辨率截图 (聊天软件压过的、缩放过的小图)会让「看着像」和「实际色值」差很远。全程用像素测量。

五步流程

1. 网格定位,不要手填坐标

参考图通常是等距排布的元素表。用浅灰分框线(低饱和 + 中亮度)做行/列投影找边界:

def is_line(r,g,b):
    mx,mn = max(r,g,b), min(r,g,b)
    return mx-mn < 16 and 170 <= mx <= 240      # 浅灰框线
# 对整列像素计数 → 峰值即竖线位置;相邻很近的两条合并(同一根线的两沿)

坑:别用 --window-size 之外的方式硬编码坐标——不同图的边距差几个像素, 换算到 viewBox 就是几度偏差。也别一次全图统一阈值,某些行的框线更淡会整行漏掉, 必要时逐行检测。

2. 配色:腐蚀一次取量化众数

# 分类:max-min < 50 或 s < 0.42 的算灰/白,不参与配色
# 腐蚀:只保留「上下左右四邻都是同色系」的像素 = 色块/笔画内部
mode.setdefault(family, Counter())[px] += 1
# 再按 8 级量化合并(压缩噪点会把同一个色散成好几个近似值),取众数

不要用「最饱和 N% 像素的中位数」——两个坑:

  • 被混色暗边带偏(暗色像素的 HSV 饱和度反而更高,越暗越"饱和");
  • 被更粗的元素带偏。实测一张麻将牌面参考图上,万字那一行的蓝是偏紫的 #241464,而筒点是 #3c5474,根本不是同一个色。所以要逐行/逐区域统计, 混在一起只会得到一个谁都不像的中间值。

3. 元素测量:连通域 + 换算

4/8 连通域扫出每个图形元素,输出 bbox / 中心 / 尺寸,再线性换算到 viewBox:

vbx = cx / cell_w * 100            # viewBox 宽 100
vby = cy / cell_h * 138            # viewBox 高 138 —— 注意用**各自的高度**换算

关键:参考图的单格宽高比往往和目标不同(例:参考 84×105 = 0.80,实际牌面 42×58 = 0.72)。所以 x 按宽度百分比、y 按高度百分比分别映射,牌面会被"拉高", 这正是真实牌的样子;千万不要按同一个比例缩放(元素会变形或对不齐)。

连通域会碎片化(细笔画的环被走线切断),所以:

  • 先按中心坐标聚类再读位置,而不是指望每根笔画出一个完整框;
  • 同一元素被拆成 2~3 块时,取它们 bbox 的并集。

4. 比例关系靠「剖面」而不是目测

同心圆、环、渐变这类结构,沿半径统计彩色像素占比就能读出每层半径:

for r in [i/2 for i in range(0, 34)]:
    hit = sum(1 for a in range(72) if colored(cx + r*cos(a), cy + r*sin(a)))
    print(r, hit*100/72)      # 100=纯色环,≈0=白环

实测得到「实心圆 → 白 0.63R → 彩 0.50R → 白 0.24R → 彩芯 0.13R」这种精确比例, 比"看起来大概是一半"靠谱得多。

5. 验证:并排对照页 + 结构计数断言

(a) 并排对照页——用 CSS background-position 裁参考图,和本项目渲染并排:

                  /* 单格高/宽 百分比,保持比例 */

整页截图后一眼就能看出「哪一张对不上」。这是唯一能证伪的手段—— DOM 断言只能证明 SVG 里有这个字符串,证明不了它画出来像不像。

(b) 结构计数断言——把「语义」变成可数的结构,写进测试:

n + '筒' → 恰好 n 个圆点(每点 5 层同心圆)→ 数 
n + '条' → 恰好 n 根竹                    → 数 
六条应是 3 列(不是 2 列)→ new Set(x 坐标).size === 3
九条中间一列为红 / 九筒中间一行为红 → 数色值出现次数

这类错误肉眼极难发现(六条排成 2×3 看着也挺自然),必须靠计数兜住。

新断言必须亲手改坏一次确认它会失败。 验证时注意:改「点的排列顺序」不会 触发列数断言(列数没变),要真的改列数。永远通过的新断言等于没有断言。

描边宽度的亚像素陷阱

SVG 单位 ≠ 屏幕像素:牌面 42px 宽时缩放比只有 0.42,viewBox 里 3 个单位的描边 只有 ~1.26px,再细就会被抗锯齿糊成浅色。所以:

  • 描边宽度设下限:max(3, min(w,h) * 0.24);
  • 参考图上很亮的颜色(对比度 < 4.5:1)直接用会显得"没画上去", 按目标尺寸适当压暗并记录理由(本项目把参考图的绿 #3c844c(4.23:1) 压到 #16663a(6.27:1))。

配套脚本

项目里留一份 scripts/read_ref_tiles.py(同类项目可直接抄):网格定位 + 逐行配色 + 逐格连通域测量,输出已换算好的 viewBox 坐标。

工作流顺序(省时间的排法)

  1. 先跑测量脚本,把全部尺寸色值拿到手(别边看边猜);
  2. 按测量值一次性写完绘制代码,node --check 过语法;
  3. 生成对照页截图 → 修正偏差;
  4. 补结构计数断言 + 负向验证;
  5. 最后才做真机尺寸(1:1)可读性检查:用「外层 div 精确裁剪 + 内层 iframe 负 margin」 绕过无头浏览器视口钳制(Windows 无头最小视口宽 ~504),才能看到真实像素。

Related skills

Generate and edit Draw.io, Mermaid, and Excalidraw diagrams from natural language using a structured JSON spec.

by nssa.io1.0k installs47 stars

Find why your productivity system keeps failing, then apply the smallest fix — capacity math, bottleneck routing, durable local notes.

by Iván855 installs69 stars

Fetch raw ad creative, app, ranking, and revenue data from AdMapix as structured JSON.

by fly0pants4.3k installs296 stars

Stores durable facts in a categorized, plain-markdown vault on disk, alongside your agent's built-in memory.

by Iván559 installs18 stars

Join a video meeting as an AI bot with voice, avatar, and screenshare across four operating modes.

by johnpatternai22 installs8 stars

Run Git operations — commits, branches, merges, rebases, conflict resolution, and recovery — with safety rules enforced.

by Iván535 installs31 stars

More from oracis

Browse all skills

把本地 Skill 打包并发布到 SkillHub(腾讯 skillhub.cn)与 ClawHub,覆盖预检、发布、状态回读与竞品对标全链路,并在上传被拒时用二分/ddmin 脚本把「服务端 WAF 拦内容(566)」与「包结构/字段问题」精确区分开。当用户说「发布技能到市场」「上架 skill」「SkillHub 提交失败」「Failed to fetch」「566」「上传 zip 报错」「技能审核状态」「版本号被拒」时使用。也讲清「入库成功 ≠ 已公开」——用 `mine` 的 `reviewStatus`、重发探测 `409 VERSION_EXISTS`、`/versions/<v>/signature` 三个探针判断版本到底走到哪一步。

by oracis1 installs1 stars

平台只有网页后台、没有上传 API 时,用本机已装的 Chrome/Edge + CDP 自动化走完上传/发布/填表流程——复用真实登录态、零安装(不下载 500MB Chromium)、能给文件选择框塞文件;并实测富文本编辑器(公众号 / CMS / 邮件模板)里到底哪些 CSS 能活下来,以及在决定是否接入平台自带的「一键排版 / AI 美化」前先抓它输出做结构化 diff。当用户说「只能网页上传」「后台发布」「网页填表自动提交」「发布到技能市场/各平台控制台」「复用已登录的浏览器」「公众号排版样式不生效/保存后样式没了」「一键排版要不要用」「点了按钮没反应/提交没成功也没报错」时使用。

by oracis2 installs

一键安装并实测验证已验证可用的免费 LLM 到 WorkBuddy/Claude Code,无需注册、无需 API Key。当用户说「装免费模型」「加免费模型」「免费 LLM」「免费模型一键装」「验证免费模型可用吗」「免费模型怎么接入」「帮我配几个免费模型」「监控免费模型」「免费模型挂了吗」「kilo 网关」「kilo-auto」「nemotron 免费」「space-bunny」「智谱 glm 免费」「zhipu 免费」「glm-4-flash」「glm-4.7-flash」「glm-z1-flash」「glm-4v-flash」「探测国外免费模型」「国外平台免费 llm」「优先用免费模型」「读图桥接」「vision bridge」「给 glm-4-flash 加读图」「不读图的模型怎么看图」「阶跃星辰」「stepfun」「step 5」「step-5-preview」「限时免费模型」「ccproxy 读图转发」「给 claude code 加读图」时使用。也用于验证已有免费模型配置是否真的可用(tool calling 是否支持、是否限流、是否支持读图),以及定期 watch 监控免费模型是否下线/限流/失去工具调用能力。

by oracis1 installs

在中国大陆网络环境下用 yt-dlp 下载视频(含 Windows GUI 封装)。当用户要下载 YouTube、Bilibili、SoundCloud 等 yt-dlp 支持的站点内容,或遇到「yt-dlp 装不上 / 下载报 502 / Tunnel connection failed / ffmpeg not found / 缺 JS runtime / TLS fingerprint / watch?v=&list= 把整个列表都下了 / Sign in to confirm you're not a bot / The page needs to be reloaded / 下到一半突然下不动 / 下回来的视频糊、有拖影残影 / 下载速度特别慢」等问题时使用。

by oracis2 installs

聚合搜索百度网盘/夸克网盘/阿里云盘等网盘分享链接。当用户想按作者名、课程名、剧名、书名、软件名找网盘下载路径,或提到「网盘搜索」「PanSou」「盘搜」「找到下载链接」「夸克/百度/阿里网盘资源」时使用。包含已验证的 PanSou 协议端点、绕过系统代理的必要写法、以及可直接运行的本地 Web 应用 panradar.py。

by oracis2 installs

在 WorkBuddy(Windows)环境里交付零依赖本地 Web 应用,并绕开官方测试技能完全不覆盖的本机专属坑。当用户要在本机跑起来一个本地 Web 应用 / 单文件工具 / 案例库 / 看板 / 小工具,或要验证刚写完的 HTML/JS/Python 交付物真的能工作时使用。独家覆盖:Bash 缺 coreutils、bash 是 WSL 启动桩、rm 是坏 shim、PowerShell 不回显 stdout、cwd 漂移、预览面板靠 HEAD 探活——这些在干净 Linux 环境里遇不到。

by oracis1 installs