关于 pixelfx
pixelfx 是用代码绘制像素艺术效果的工具集,适用于 JavaScript 游戏开发者及需要导出动画素材的团队。效果可实时调整颜色、方向和随机种子,也可渲染为精灵图集供其他引擎使用。
主要功能
- 01以代码绘制双缓冲像素效果
- 02调整调色板、方向、光效和种子
- 03渲染精灵图集与动画帧
- 04检查循环、画布边界与性能
适用场景
- 01在 JavaScript 游戏中实时播放效果
- 02为 Godot 或 Unity 导出动画图集
- 03制作并检查角色攻击效果
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ patch-gg/ pixelfx --skill pixelfx安装后在 Claude Code 中输入/pixelfx确认已加载。
详细介绍
pixelfx
将像素艺术效果编写为代码。每个效果都是一个文件,src/fx/<category>/<name>.js,绘制到两个缓冲区中:
color(像素:不透明、抖动或真正半透明)和 light(加色发光)。无需图像,因此效果可以实时播放、重新着色、镜像、重新设定随机种子,并渲染成适用于任何引擎的精灵图集。
此方法来自 Hugo Duprez(如何用 Claude 制作(出色的)像素艺术效果):代码是黏土,相信你的眼睛,提供参考素材。一次性提示词只能生成平庸的效果。将草稿渲染出来、仔细观察并不断改进,才能做出好效果。
开始之前
- 在 pixelfx 检出目录中操作。如果工作目录下没有
tools/render.mjs,就在项目旁克隆一份:git clone https://github.com/patch-gg/pixelfx。无需安装:这些工具只用到 Node。 - 检查能否运行:
node tools/render.mjs fire/torch会写入records/fire/torch/contact.png。用你的图像读取工具打开这个 PNG。从现在起,你可以通过这张联系表查看每个效果。
1. 先查找现有的效果
node tools/list.mjs <words> 会搜索 ID、名称、标签和描述(node tools/list.mjs frost、node tools/list.mjs slash loop)。docs/CATALOG.md 按类别列出了所有效果。先渲染候选效果并查看,再做选择。大多数需求都可以通过调整现有效果的选项来满足:
palette:主色阶,从暗到亮,以十六进制字符串表示。可以使用src/core/color.js中的任意PAL色阶(fire ember lava smoke dust ice water electric volt poison holy heal arcane shadow blood earth stone gold leaf wood metal bone neon cyber matrix candy night),也可以使用自己的色阶。蓝色火焰可以这样指定:{"palette": PAL.ice}。seed用于生成不同但等效的效果;flip用于朝左;angle用于旋转;light(0..1+)用于调整辉光强度;还可以设置每个效果在其meta.options中的专属参数(大小、数量、半径、文本、高度……)。- 无需编辑代码即可试用选项:
node tools/render.mjs fire/torch --opts '{"palette":["#102","#215","#43a","#8cf","#fff"]}'。
2. 放进游戏
使用 JS 或 TS 的 Canvas 或 WebGL 游戏(原生 canvas、Phaser、PixiJS、Kaplay、three.js):直接使用代码即可。它
没有依赖;复制 src/core 和所需的效果文件,或依赖此仓库。
import { createFrame, clearFrame, createFx, composite } from "pixelfx"; // src/core/index.js
import * as frostNova from "pixelfx/fx/ice/frost-nova"; // src/fx/ice/frost-nova.js
const frame = createFrame(320, 180); // the game's pixel resolution; ox, oy scroll it with the camera
const img = new ImageData(320, 180);
const fx = createFx(frostNova, { x: hero.x, y: hero.y, flip: hero.facing < 0 });
// every tick
fx.update(dt);
clearFrame(frame);
fx.draw(frame, "back"); // what goes behind characters
drawCharacters(); // your own sprites, or draw them into frame.color yourself
fx.draw(frame, "front");
composite(frame, img.data, background); // color over the background plus light; or null for transparent
ctx.putImageData(img, 0, 0); // then scale the canvas up with image-rendering: pixelated
if (fx.done()) removeIt(); // one-shots end on their own; fx.stop() fades a loop out
多个效果可以共用一帧。在 WebGL 引擎中,每帧将合成后的 RGBA 上传到纹理,或者将效果一次性渲染到精灵图(见下文),然后像播放其他动画一样播放。
任何引擎(Godot、Unity、GameMaker、Defold、LÖVE、Bevy、Construct):导出精灵图。
node tools/render.mjs ice/frost-nova --sheet 会生成 records/ice/frost-nova/frost-nova.png(网格排列的透明帧)和
frost-nova.json(Aseprite 风格的帧数据,因此 Phaser 的图集加载器、Godot 和 Unity 的 Aseprite
导入器以及大多数工具都能读取;meta.pixelfx 包含 fps、循环、帧尺寸、列数和轴心点)。将
轴心点设为 meta.pixelfx.pivot(效果的原点,例如脚部),以最近邻过滤且不压缩的方式导入,并按
meta.pixelfx.fps 播放。辉光会以带 alpha 的颜色烘焙到精灵图中,在暗色场景上会呈现叠加效果;对于明亮场景,可渲染重新着色的版本,或将效果放在暗色图层上。
如需完整素材库:node tools/render.mjs <category> --sheet 会处理整个分类。
命中效果需要有角色作为衬托。 单独的效果看起来像贴纸。带有角色的效果附带一个 act:角色何时蓄力、何时定格,以及目标如何反应。根据游戏的构建方式选择使用:
- 使用内置角色:用
createAct(slash, { x, y })代替createFx。调用act.update(dt)、act.draw(frame),并通过act.shake抖动画面。冻结期间它会自动保持静止。node tools/act.mjs <id> --sheet会将所有内容烘焙到精灵图中。 - 使用游戏自带角色:读取时序信息,即
slash.act,或精灵图 JSON 中的meta.pixelfx.act(包含windup、recovery,以及带有t和freeze的hits)。在效果出现前windup秒播放角色的攻击动画,并在每次命中时停止更新所有内容,包括效果和角色,持续freeze秒。宿主端的命中定格适用于任何效果,无论是否带有act。
src/fx/moves/ 包含由效果串联而成的完整攻击,从蓄力到收招:有人需要招式时,从这里开始找,而不是从效果开始。
3. 制作新效果
先阅读 docs/AUTHORING.md:其中定义了约定(meta、纯效果使用 draw(p, t, o),模拟效果使用 create(o)、局部坐标、无缝循环、结束时画面为空)、工具包、绘制器 API 和质量标准。
然后:
- 用一句话描述艺术方向:它是什么、如何运动、采用什么配色、时长如何。“冰霜新星: 晶体从脚下向外呈环状迸发,中心闪出一道白光,碎片旋转飞散,地面留下冰霜并逐渐消退。”
- 查找参考:在素材库中运行
node tools/list.mjs <words>,然后阅读最接近的两三个特效文件,并借鉴其中的技巧(用于火花、烟雾和碎屑的src/core/sim.js中的Particles和Bits、用于半透明体积的p.disc、用于无缝粒子的cycle、用于火焰和水流的tileFbm滚动)。也看看 Hugo Duprez 的特效 中最接近的作品:它们是品质标杆。如果他的作品在屏幕上尺寸相同时有更多细节、光效或生命力,你的作品就还没完成。 - **起草。**运行
node tools/new.mjs <category>/<name>(循环动画请添加--loop)即可生成可用文件。如果方向尚未确定,就写 3 到 5 个真正不同的草稿(<name>-a.js..-e.js),全部渲染(node tools/render.mjs "<category>/<name>-"),并查看每张联系表后再做选择。如果用户在场,向其展示最出色的两三个版本(--gif可生成便于分享的动画)。 - **观察、评判、修改。**渲染后打开
records/<id>/contact.png,像挑剔的像素画师一样进行评判。修复最糟糕的问题,然后再次渲染。至少迭代三轮;精品特效需要更多轮。--all可显示每一帧,--mp4可全速展示动画。 - 如果涉及角色,就演出来:添加
export const act(参见docs/AUTHORING.md中的“Acts”),包含 t = 0 之前的蓄力、释放帧上的姿势变化、接触时的定格以及恢复动作。node tools/act.mjs <id>会以 12 fps 显示连续步骤:根据这些步骤和--mp4判断动作,不要只看联系表中的采样帧。 - 检查。
node tools/check.mjs <id>会检测画布外绘制、结束时画面不为空的一次性动画、循环衔接、未设种子的随机性和慢帧;对于动作,还会检测顺序错误的按键、未知姿势字段以及瞬移的手部。持续修复,直到检查完全通过。删除未保留的草稿。
需要关注的方面及常见修复方法:
| 你看到的情况 | 修复方法 |
|---|---|
| 以 1x 查看时显得模糊一团 | 减少颜色,轮廓清晰,突出一个焦点,形状更大 |
| 出现斑点:形状内部有孤立的噪点像素 | 降低阈值噪声,用 at() 量化,小形状上不加噪声 |
| 飘忽无力,缺乏冲击感 | 快速进入、缓慢退出(ease.outQuart/outExpo),加入 1 到 2 帧的白色主帧,缩短总时长 |
| 僵硬或机械 | 让每个粒子各不相同(大小、速度、延迟、寿命),添加次要动态效果(火花、烟雾、碎屑) |
| 颜色发白 | 减少辉光(k 取 0.2 到 0.5),边缘色阶更暗,只让最亮的核心部分保持白色 |
| 画面平淡 | 让光线从一侧照来:左上角更亮,右下角色阶更暗;底部增加更暗的色阶 |
| 渐变平滑,显得像矢量图 | 使用明确的色阶;只在光线和半透明烟雾中使用柔化效果 |
| 烟雾位置出现棋盘格 | 使用 SMOKE、VAPOUR 或 DUST 粒子,或使用 p.disc:真正实现半透明,并在顶部受光 |
| 循环衔接处出现接缝 | 使用 cycle、loopNoise(phase)、滚动整格的 tileNoise、sin(phase * TAU * n) |
| 单次效果突然消失 | 在 t = duration 之前让效果缩小、通过抖色淡出或飘落消失 |
| 效果很棒,但角色毫无反应 | 为角色设计一套动作:蓄力、释放姿势、接触时定格、目标做出反应、恢复动作 |
| 动作显得没有重量 | 朝打击的反方向蓄力,延长定格时间(最长 0.2 s),让轮廓变化更明显,并加入震动 |
| 打击时机不同步 | 将打击关键帧移到效果自身的常量处,而不是凭感觉估计一个时间点 |
| 角色握武器的姿势不对 | 肘部保持弯曲,武器杆在胸前;挥动时刀刃滞后于手部;手臂伸展距离约为 15 px,且不会拉长,因此要让身体向前迈步 |
| 手臂交叉,或姿势显得平板 | 角色以四分之三角度面向我们:张开手臂时,近侧的手向左(fx < 0),远侧的手向右,并设置 turn: 1;yaw 才会真正转动角色 |
方向性效果朝右,地面效果位于 y = 0,角色效果使用 o.actor(24 x 38 标准角色的蒙版和像素),且不使用 Math.random。通用主题可以使用;切勿复刻特定游戏的精灵图、角色或徽标。
4. 使用原生代码而非 JS
如果游戏无法运行 JS,而精灵图表又不够用(例如效果需要跟随移动目标,或在运行时按实例设置颜色),就移植该效果。纯效果是时间的函数;模拟效果则在 src/core/sim.js 中逐步更新粒子。保留双缓冲思路、用于抖色 alpha 的 4x4 Bayer 阈值,以及调色板色阶查找。并排渲染 JS 原版和移植版本,检查两者是否匹配。