骰子表情包 1-6 这套东西,说白了就是把一颗六面骰子的六个面,拆成六张独立的正方形图片,点数固定、结果可控,发哪张全凭你挑。它解决的是一个很具体的小问题:聊天软件自带的骰子表情是随机算法掷出来的,你没法指定结果,而这六张图可以。整套素材通常做成透明背景的 PNG,尺寸统一、风格一致,导入表情面板之后随手一发就能用,所谓“一键抱走”指的就是打包下载、批量导入这一步。这套内容适合三类人看:想给群聊和线下桌游添点乐子的普通用户,想自己做一套专属风格素材的设计新手,以及想把这套流程摸透、顺手复用到其他图标批量生成上的开发者。下面的内容会从点阵规范、尺寸换算一直讲到脚本批量生成、压缩打包和导入排查,代码和参数都能直接抄。
1. 先想清楚:这套素材到底在做什么
1.1 “作弊”二字的真实含义:把随机换成可选
聊天软件里那个骰子表情,背后是一段随机数逻辑,点下去之前谁都不知道会出几点,它的价值就在于“不可控”。而自定义骰子图片做的事情正好相反——六个面各拍一张照片,你需要几点就发哪张,随机性被彻底剥离,结果从“听天由命”变成了“菜单点菜”。所谓“作弊专用”,说的是这个机制上的替换,不是什么破解手段,任何软件都没被改动,你只是用一张图盖住了随机结果而已。
理解这一点很关键,因为它决定了整套素材的技术要求:它不是一张能动的表情,而是一组静态图;它不需要任何插件或特殊权限,只要聊天软件支持发本地图片就能用;它的“真实感”完全来自视觉一致性——六张图的尺寸、留白、点径、颜色必须严格统一,只要有一张的画风飘了,明眼人一眼就能看出这不是同一副骰子。所以做这套东西,重点不在“图好不好看”,而在“六张图是不是像同一个模子里刻出来的”。
我在第一次做的时候就没注意这点,前面三张用手绘的方式随便点了点,后面三张换了个工具画,结果点径差了大约 8%,发到群里连着刷六张,第五张明显“胖”了一圈,当场翻车。后来我把六个面的坐标全部写进一张表里,用同一套参数生成,问题才彻底消失。
1.2 三种真实需求,决定你该做多重
第一种是桌游与跑团的现场判定。线下玩需要掷骰子但手边没实物,或者桌面太小摆不开,用手机发图代替是很自然的做法;这种情况下你往往是主持人或者规则执行者,点数由你公布,本来就不需要随机,用固定图反而更利索。
第二种是群聊里的轻量互动。比如抽签决定谁去买咖啡、谁先发言、分组怎么分、今天谁值班,用骰子点数做分配依据,比直接点名少一点尴尬。这种场景对画质要求不高,但对“发出去要快”要求很高,六张图必须能在一屏之内点完,命名要有序,否则每次都要翻半天。
第三种是内容创作者的素材需求。做图文、短视频、教程插画,需要一颗风格统一的骰子图标,可能还要透明背景、多倍分辨率、甚至动态版本。这种需求最讲究规范,因为素材可能被放大到 800px 甚至更大,一点瑕疵都会被看得很清楚。
三种需求对应的制作投入完全不同。第一种用现成的矢量软件手搓半小时就够;第二种最好走脚本批量生成,五分钟出全套;第三种得考虑多尺寸导出、动图、甚至做一套换肤版本。先想清楚自己属于哪一类,再决定要不要往下读代码部分。
1.3 先把边界划清楚:能玩到什么程度
有件事必须放在最前面讲明白。这套素材的性质是“静态图片替代随机结果”,它天然带有误导性,所以在使用场景上必须自己给自己划一条线。
涉及财物的场合一律不碰,任何形式的押注、抽奖分钱、以点数定输赢的金钱往来,都不要用这套图,这已经不是玩笑了。涉及他人真实决策的场合也不要碰,比如用点数决定谁承担某项实际责任、谁去执行某个有代价的任务,对方以为这是随机结果,实际上是你安排的,这就变味了。公开场合使用前先看一眼群规,很多社群对刷屏和“假随机”有明确限制,被提醒一次不丢人,被踢出去就难看了。
我自己的习惯是:发之前先说明“这是我自己做的骰子图,点数我选的”,把它当个明牌的魔术来玩,大家的反应反而更好。真正让人觉得不舒服的从来不是图本身,而是那种“我骗到你了”的得意劲儿。
2. 底层设计:点阵规范与素材参数怎么定
2.1 六面点数的经典排布,先记牢这张表
骰子的点数排布不是随便点几个圆,它有一套流传很久的固定规则:相对的两面点数之和为七,而每个面内部的点位分布也有约定俗成的样式——一点居中、两点对角、三点对角线加中心、四点四角、五点四角加中心、六点分两列各三个。这套规则的意义在于,即使点数被遮挡一部分,人眼也能快速辨认出是几。
做素材的时候,必须严格照这套规则来,否则会出现“看起来像五又像六”的尴尬。下面这张表是我自己用的坐标对照,以 3×3 的九个格位来标记(左中右 × 上中下),格位编号从左上开始按行数:
| 点数 | 占用的格位 | 视觉特征 |
|---|---|---|
| 1 | 中心(第 5 格) | 单点居中,最简洁 |
| 2 | 左上、右下(第 1、9 格) | 对角分布,留白多 |
| 3 | 左上、中心、右下(第 1、5、9 格) | 主对角线 |
| 4 | 四角(第 1、3、7、9 格) | 对称,视觉最稳 |
| 5 | 四角 + 中心(第 1、3、5、7、9 格) | 最饱满的单数 |
| 6 | 左列三格 + 右列三格(第 1、4、7、3、6、9 格) | 两列三点,注意不是两行 |
这里最容易出错的是六点。很多人下意识画成上下两行各三个,那是横向的排法;传统骰子的六点是竖向两列各三个,因为骰子六个面的布局需要在任何角度下都能快速区分。这一点如果你做的是给桌游玩家看的素材,画错了会被立刻指出来。
提示:如果你的素材是给特定游戏规则配套的,先确认那套规则有没有自定义排布,别想当然套传统样式。
2.2 尺寸、留白、点径的换算过程
参数不能拍脑袋定,得算。假设你要做 240×240 的画布(这是主流聊天软件表情面板最常见的正方形规格),整个设计可以按下面的逻辑推:
第一步定安全留白。图片在聊天界面里显示时,边缘可能被圆角裁切或与背景贴合,所以内容不能顶到边。取画布边长的 10% 作为留白,240 × 10% = 24px,实际绘制区域就是 192×192。
第二步定点位坐标。把 192px 的区域三等分,每份 64px,格位中心分别落在距绘制区左边缘 32px、96px、160px 的位置,加上 24px 的偏移,实际坐标为 56、120、184。纵向同理。这样九个格位的圆心坐标就全确定了,六个面共用这一套坐标,绝对不会出现点偏。
第三步定点径。点径太大会让五点、六点挤在一起,太小则在小尺寸下糊成一团。经验值是绘制区边长的 17%~18%,192 × 0.175 ≈ 34px,取偶数 34px 比较好算半径(17px)。六点的情况下,相邻两点的圆心距是 64px(同行)和 64px(同列),34px 的直径意味着间隙还有 30px,视觉上不会粘连。
第四步检查最小间距。左上角点到画布边缘的距离是 56 - 17 = 39px,剩余空间充足,即使被裁掉一圈也不影响辨认。这套数字你可以整体按比例缩放,比如做 480×480 就用 48px 留白、68px 点径,比例关系保持不变,导出的图在任何尺寸下观感都一致。
2.3 颜色、描边、透明背景,三个取舍
颜色上我踩过的坑最多。第一种做法是黑点白底,最经典,但发到深色主题的聊天界面里,白色方块的边缘会非常突兀,像贴了张纸。第二种是黑点透明底,适配性最好,深色浅色背景都能融进去,但黑点在深色背景上会直接消失,等于白做。第三种是同色系方案,比如深灰点配透明底,在浅色背景上清晰,在深色背景上勉强可见。
实测下来最稳的是“自适应描边”:主体用深色圆点,外面加一圈 2~3px 的浅色描边(或者反过来,浅色点配深色描边)。这样无论背景是深是浅,总有一层能提供对比。缺点是描边会让图看起来稍微“肉”一点,不够干净,所以要控制描边宽度不超过点径的 10%,34px 的点径对应 3px 描边刚刚好。
背景一律用完全透明,不要用纯白。理由很实在:透明背景的图在发送时,聊天软件通常不会再加底色,能直接融进气泡;而白底图会被当成一张“照片”,很多软件会给它加一圈细边或者圆角,六张图的边距一旦不一致,看起来就像六张不同的图。透明底的代价是要注意深色主题下的可见性,这就回到了上面描边的问题,两者必须一起考虑。
3. 三条制作路线,按基础挑一条走
3.1 路线一:矢量软件手搓,适合完全零基础
不需要写任何代码,任何主流矢量绘图软件都能做。流程是:新建 240×240 画布,拉一条参考线定出 24px 的内边距,再拉四条线把中间区域分成 3×3 的九宫格,然后在需要的格位中心画圆,直径 34px,填充深色,加 3px 浅色描边,最后一组六个画板分别摆好点位导出 PNG。
这条路线最大的好处是所见即所得,你可以随手调整点的圆润度、描边粗细、甚至给圆点加一点点渐变让它更像实物。缺点是一致性完全靠手工保证,六个画板如果不用“符号”或“组件”功能复用同一个圆,很容易出现尺寸偏差。我的建议是:先画好一个标准圆,把它转成符号或组件,然后所有点位都从符号库里拖,这样改一次圆心直径,六个面同步更新,不会出现“第五张胖一圈”的事故。
导出的时候记得勾选透明背景、关闭“使用画板尺寸裁剪”之外的任何自动缩放,分辨率导出 1x、2x 各一套,1x 用于聊天,2x 用于图文素材。
3.2 路线二:脚本批量生成,五分钟出全套
如果你要做的规格比较多(比如同时要 240、480、800 三个尺寸,还要两套配色),手搓就太慢了。用 Python 加 Pillow 写个脚本,参数一改全部重出,是最省事的做法。
from PIL import Image, ImageDraw # ===== 参数区:改这里就能换尺寸和配色 ===== SIZE = 240 # 画布边长 MARGIN_RATIO = 0.10 # 留白比例 DOT_RATIO = 0.175 # 点径占绘制区比例 DOT_COLOR = (32, 32, 32, 255) # 点的颜色(RGBA) RING_COLOR = (245, 245, 245, 255) # 描边颜色 RING_WIDTH = 3 # 描边宽度 OUT_DIR = "./dice" # ===== 点位定义:用九宫格索引 1-9 ===== FACES = { 1: [5], 2: [1, 9], 3: [1, 5, 9], 4: [1, 3, 7, 9], 5: [1, 3, 5, 7, 9], 6: [1, 4, 7, 3, 6, 9], } margin = round(SIZE * MARGIN_RATIO) # 24 inner = SIZE - margin * 2 # 192 dot_d = round(inner * DOT_RATIO) # 34 step = inner / 3 # 64 # 九个格位的圆心坐标 centers = {} for row in range(3): for col in range(3): idx = row * 3 + col + 1 x = margin + step * (col + 0.5) y = margin + step * (row + 0.5) centers[idx] = (x, y) import os os.makedirs(OUT_DIR, exist_ok=True) for face, cells in FACES.items(): img = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 0)) # 全透明底 draw = ImageDraw.Draw(img) r = dot_d / 2 for c in cells: cx, cy = centers[c] box = [cx - r, cy - r, cx + r, cy + r] draw.ellipse(box, fill=DOT_COLOR, outline=RING_COLOR, width=RING_WIDTH) img.save(f"{OUT_DIR}/dice_{face}.png") print(f"face {face} -> {dot_d}px dots")这段代码有几个细节值得说。留白和点径都用比例而不是固定像素算,所以把SIZE改成 480,其余参数会自动跟着缩放,不需要逐项改。绘制时用RGBA模式的透明底,ImageDraw.ellipse的width参数负责描边,描边是画在圆的内侧的,所以实际点径会比视觉上略小一点点,视觉上反而更精致。
FACES里六点的顺序是[1, 4, 7, 3, 6, 9],按左列从上到下、右列从上到下的顺序画的,虽然绘制顺序不影响结果,但这样写和上文的排布表对得上,日后维护不容易看错。
跑完你会发现一个问题:所有圆都是硬边的,放大看会有锯齿。要解决就开超采样,把画布放大四倍画,最后缩回来:
SCALE = 4 BIG = SIZE * SCALE img = Image.new("RGBA", (BIG, BIG), (0, 0, 0, 0)) draw = ImageDraw.Draw(img) r = dot_d * SCALE / 2 # 坐标和尺寸全部乘 SCALE,画完再缩 img = img.resize((SIZE, SIZE), Image.LANCZOS)超采样之后边缘会顺滑很多,代价是生成慢个几十毫秒,完全值得。
3.3 路线三:网页端 Canvas,一点即导出
不开编辑器、不装环境,直接在浏览器里跑一段 HTML,点按钮就能把六张图存下来,适合分享给不懂代码的朋友用。
<!DOCTYPE html> <html> <body> <script> const SIZE = 240, MR = 0.10, DR = 0.175, RW = 3; const FACES = {1:[5],2:[1,9],3:[1,5,9],4:[1,3,7,9],5:[1,3,5,7,9],6:[1,4,7,3,6,9]}; const margin = SIZE * MR, inner = SIZE - margin * 2; const dotD = inner * DR, step = inner / 3; function centers() { const m = {}; for (let r = 0; r < 3; r++) for (let c = 0; c < 3; c++) { m[r * 3 + c + 1] = [margin + step * (c + 0.5), margin + step * (r + 0.5)]; } return m; } const C = centers(); function make(face) { const cv = document.createElement("canvas"); cv.width = cv.height = SIZE; const ctx = cv.getContext("2d"); FACES[face].forEach(i => { const [x, y] = C[i]; ctx.beginPath(); ctx.arc(x, y, dotD / 2, 0, Math.PI * 2); ctx.fillStyle = "#202020"; ctx.fill(); ctx.lineWidth = RW; ctx.strokeStyle = "#f5f5f5"; ctx.stroke(); }); return cv; } for (let f = 1; f <= 6; f++) { const cv = make(f); const a = document.createElement("a"); a.download = `dice_${f}.png`; a.href = cv.toDataURL("image/png"); document.body.appendChild(a); a.textContent = `下载 ${f} 点`; a.style.display = "block"; } </script> </body> </html>存成.html双击打开,页面上会出现六个下载链接。Canvas 默认就是透明背景,arc画圆自带抗锯齿,比 Python 版省了超采样那一步。缺点是导出尺寸固定为SIZE定义的值,要改尺寸得改代码,不像 Python 版可以循环批量出多个规格。如果你要做多尺寸,在make里加一层循环,创建不同尺寸的 canvas 分别导出即可。
3.4 想要“滚一下”的效果,动图怎么做
静态图用久了会觉得太平,加个滚动动画会生动很多。思路是把一张骰子图从“虚化旋转”到“定格落位”,做成 8~12 帧的循环图。
做法上,最省事的是用 GIF:先生成六张静态图,再用图像处理库把中间过程插值出来,每帧旋转角度递增、透明度渐变,最后三帧定格在目标点数上。参数上控制帧数在 10 帧左右、单帧时长 80~100 毫秒,整体时长 1 秒左右,超过 1.5 秒观众就失去耐心了。
体积是最麻烦的地方。GIF 只支持 256 色,边缘会有色带;每帧全画布刷新,体积容易失控。实测 240×240、10 帧的 GIF 大概在 20~40KB,压缩到 8 帧、降低中间帧的颜色数可以再降一半。如果能接受,用 WebP 或者 APNG 效果更好,但兼容性要自己掂量——很多聊天软件对这两种格式的支持不完整,发出去可能变成静态图。
注意:动图版本的文件体积上限通常比静态图严格得多,做之前先确认你要投放的环境对体积的限制,别做完才发现发不出去。
4. 从六张图到一个“抱走包”
4.1 命名和目录结构,决定导入会不会错乱
命名这件事看起来是小事,实际上决定了整套素材好不好用。聊天软件的表情面板一般按文件名或添加顺序排列,如果你的文件叫dice1.png、dice2.png,中间插进去一个dice_final.png、dice_new.png,顺序立刻就乱了,每次发骰子都要翻半天找。
我的做法是严格用两位数编号加重语义:dice_01.png到dice_06.png,编号和点数一一对应,文件名的字母部分统一,只有数字变化。这样在文件管理器里排序稳定,导入表情面板之后顺序也稳定,靠肌肉记忆就能点中想要的那一张。
如果有人要同时保存多个风格版本,用目录区分而不是文件名区分:
dice-pack/ ├── classic-240/ # 经典黑白 240px │ ├── dice_01.png │ ├── ... │ └── dice_06.png ├── classic-480/ # 同款高清 480px ├── dark-mode/ # 深色适配版 ├── animated/ # 动图版 └── README.txt # 说明文件这样别人下载之后,想要哪一套进哪个目录拿,不会拿混。我见过有人把六张图和三套配色全平铺在一个文件夹里,一共十八个文件,找起来比重新画还费劲。
4.2 体积压缩实测,别让“抱走”变成“搬不动”
纯色透明 PNG 本身的压缩效率就很高,因为大片区域像素值完全相同,压缩算法处理起来很轻松。但很多人导出时不注意,用了带抗锯齿边缘的高分辨率图,体积一下就上去了。
我做过一组对比,同样是 240×240 的骰子图,六张一套:
| 方案 | 单张体积 | 六张合计 | 观感 |
|---|---|---|---|
| PNG-24 全彩透明,2x 缩放后缩回 | 4~6KB | 约 30KB | 边缘顺滑,最推荐 |
| PNG-24 直接绘制,无抗锯齿 | 2~3KB | 约 15KB | 放大有锯齿 |
| PNG-8 索引色 128 色 | 1~2KB | 约 10KB | 边缘轻微色带,小尺寸下看不出 |
| JPEG 白底 | 8~12KB | 约 60KB | 有白底,不推荐 |
| 动图 GIF 10 帧 | 20~40KB | 单张即 30KB | 有动画,体积大 |
结论很清楚:静态图用 PNG-24 就够了,一套六张压到 30KB 上下,发微信、贴论坛都毫无压力。真正需要省体积的是动图,那时候才需要动用降帧、减色、裁剪画布这些手段。
还有一个隐蔽的体积杀手:画布尺寸不一致。如果六张图的画布有的是 240×240,有的是 242×241,看起来差不多,但打包后体积会莫名变大,导入表情面板还可能被自动拉伸。导出后一定要批量核一遍尺寸,用批量重命名工具或者一行脚本搞定:
# 批量把六张图统一裁成 240x240 并居中 for f in dice_*.png; do convert "$f" -background none -gravity center \ -extent 240x240 "out_$f" done4.3 各端导入和添加表情的实际路径
导入这件事,不同聊天软件的入口不太一样,但大逻辑是一致的:找到“表情管理”或“我的表情”,选“添加单个表情”,然后从相册里挑图。有几个实操细节值得提前知道。
第一,添加时会有一个裁剪框,一定要确认框选的是完整的正方形,不要手一滑裁掉一边,六张图裁得不一样,发出来高低不齐。第二,有些软件对添加的表情有数量上限,如果你已经存了几百个,先清理一批再导入。第三,添加后的表情通常会自动压缩,压缩之后透明背景可能变成白底,这时候要检查一下,如果变白了,说明原图的透明通道没保存好,回去重新导出。第四,添加顺序是你点击的顺序,所以要按 1 到 6 依次添加,别乱点,否则面板里的顺序就是乱的。
如果是给别人“抱走”,最友好的方式是把六张图加一份说明文档打个 zip,说明里写清楚尺寸、配色、适用场景和导入方法。一个两百字的说明文件,能省掉对方十次追问。
4.4 抱走包里的说明文档该写什么
很多人省掉这一步,结果每次分享都要重新解释一遍。说明文档不用长,四块内容足够:这套图是什么(六个面、固定点数)、参数是什么(尺寸、格式、背景是否透明)、怎么用(导入路径、注意事项)、边界在哪(不建议用于什么场合)。
最后一块尤其重要。把“不建议用于涉及财物的场合”这句话明明白白写在文档里,既是提醒别人,也是给自己留个说明。我见过有人把素材包做得精致,说明只写一句“随便用”,结果被拿去做了不该做的事,回头还得解释。写清楚,就不会有这种麻烦。
5. 常见问题与排查实录
5.1 发出去有白底、黑边、或者一圈毛刺
白底最常见,原因几乎都是导出时没勾选透明背景。有些软件在导出 PNG 时默认铺白色底,界面上看不出来,因为预览背景本身是白的。检查方法是把图拖到一个深色背景的窗口里看一眼,如果出现白框,就是没透明。
黑边则是另一种情况:图本身是透明的,但聊天软件在显示时给透明图加了描边,用来区分图片和背景。这不是你的问题,改不了,只能通过给圆点加浅色描边来缓解视觉上的割裂感。
毛刺是导出分辨率不够导致的。解决办法只有一个,超采样:按四倍尺寸绘制再缩回目标尺寸,边缘会平滑很多。
5.2 六张图看着像六副骰子
这个问题的根源永远是参数不统一。排查顺序建议是:先核尺寸,六张图的画布边长必须完全一致;再核点位,用九宫格坐标对一遍,特别检查六点是不是画成了两行;最后核点径和描边宽度,用图像编辑软件量一下圆的直径,差 2px 以上肉眼就能感觉出来。
我自己的做法是永远不手摆,全部用参数生成,哪怕只做一次。因为手工摆的过程里,你会不自觉地“看着舒服就调一下”,而每次微调的幅度都不一样,六张图摆完,参数已经飘了。
5.3 深色模式和低分辨率下的翻车
深色模式的问题前面提过:黑点透明底在深色界面上几乎看不见。解决办法是给点加浅色描边,或者干脆做两套,一套浅色适配一套深色适配,在说明文档里写清楚哪套给哪种场景用。
低分辨率的问题更容易被忽略。有些场景下图片会被缩到 48px 甚至更小显示,这时候 34px 的点径缩下来只有 7px,如果描边占了 3px,圆点几乎就成了一坨。所以做小尺寸版本时,描边要按比例减到 1px 以内,或者干脆去掉描边,只保留纯色圆点。
| 显示尺寸 | 建议点径 | 建议描边 | 备注 |
|---|---|---|---|
| 240px | 34px | 2~3px | 主用版本 |
| 120px | 17px | 1px | 列表缩略图 |
| 48px | 7px | 0 | 去掉描边,防糊 |
5.4 用着用着被提醒了怎么办
这个真会发生。有些社群对刷屏敏感,连着发六张图确认点数,在别人眼里就是刷屏。我的经验是:一次只发一张,需要展示过程的时候用合并消息或者一次发完不再重复;如果群里明确说过不许玩这类“假随机”,那就换到别的场合玩,不必较劲。
还有一种情况是别人误以为你在用官方功能,这时候主动说明一句“这是我自己做的图,点数是我选的”,既澄清了事实,也让气氛轻松下来。藏着掖着反而显得心虚。
6. 几个让我少走弯路的细节
6.1 参数表比手感可靠
做完第一套之后,我把所有参数整理成了一张表存在项目目录里:画布尺寸、留白比例、点径比例、描边宽度、六个面的格位索引。后来每次要做新配色或者新尺寸,直接改表里的数字重新跑一遍,再没出现过“这套看着不太一样”的情况。手感这东西在单张图上很管用,在需要一致性的批量任务里,它就是最大的不确定来源。
6.2 留一套“半成品”比留成品更有用
我现在习惯把生成脚本和参数表一起打包,而不是只发六张 PNG。理由很实际:别人拿到成品只能直接用,拿到脚本可以改成自己的配色、自己的尺寸、自己的圆角风格。一套素材的生命周期,往往在别人想改又改不了的时候结束。把脚本留下,它就能一直活下去。
另外还有个小扩展方向,如果你已经把这套流程跑通了,改几行参数就能做出四面骰、八面骰、十二面骰的图标,甚至做一套扑克牌点数的批量生成。核心逻辑完全一样:定义格位坐标、定义每个面占用哪些格位、循环绘制导出。真正花时间的从来不是画图,而是把“六个面用同一套规则生成”这件事想明白。