poku-pixel-fx 是做什么的?
POKU Pixel FX 是一个韩文本地化的、基于 TypeScript 的开源分支/衍生项目,源自 Patch 的 PixelFX,作为独立仓库维护,没有 GitHub 网络分支链接。上游 MIT 许可证归功于 Patch 和 Hugo Duprez;请在 LICENSE 和 NOTICE.md 中保留版权和署名声明。
需要 Node.js 18 或更高版本;ffmpeg 为 GIF 和 MP4 预览的可选依赖。
将像素艺术特效编写为代码。每个特效是一个独立的文件 src/fx/<category>/<name>.ts,会绘制到两个缓冲区中:
颜色(像素:不透明、抖动或真正半透明)和光照(叠加辉光)。无需图像,因此特效可以实时播放、换色、镜像、重新播种并渲染成精灵表,供任何引擎使用。
方法是 Hugo Duprez 的(如何用 Claude 制作(好的)像素艺术特效):代码是黏土,相信你的眼睛,提供参考。一次性的提示只能生成平庸的特效。你渲染、观察并反复打磨的草稿才能成就佳作。
准备工作
- 在包含
package.json和tools/render.mts的 Poku Pixel FX 检出目录中工作。如果没有,则在用户选择的项目或工作区中获取公共库:git clone https://github.com/Stankjedi/poku-pixel-fx.git。仅技能文件不包含特效库。切勿使用他人的机器特定路径。必要时使用npm ci安装检出目录的依赖;如果已经安装则不重复执行。 - 在使用工具或图库前运行
npm run build;编译器会将运行时模块输出到build/,CLI 工具输出到build-tools/。 - 验证其可运行:
node build-tools/tools/render.mjs fire/torch会写入records/fire/torch/contact.png。用你的图片查看工具打开该 PNG 文件。从此以后,这个联系表就是你查看每个特效的方式。
1. 首先查找现有特效
node build-tools/tools/list.mjs <words> 用于搜索 id、名称、标签和描述(例如 node build-tools/tools/list.mjs frost、node build-tools/tools/list.mjs slash loop)。docs/CATALOG.md 按类别列出所有特效。渲染候选特效并查看后再做选择。大多数需求可以通过现有特效的不同选项来实现:
palette:主要渐变带,从暗到亮,以十六进制字符串形式给出。可以是src/core/color.ts中的任意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 build-tools/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 "poku-pixel-fx"; // src/core/index.ts
import * as frostNova from "poku-pixel-fx/fx/ice/frost-nova"; // src/fx/ice/frost-nova.ts
const frame = createFrame(320, 180); // 游戏的像素分辨率;ox, oy 随摄像机滚动
const img = new ImageData(320, 180);
const fx = createFx(frostNova, { x: hero.x, y: hero.y, flip: hero.facing < 0 });
// 每帧执行
fx.update(dt);
clearFrame(frame);
fx.draw(frame, "back"); // 绘制在角色后面的内容
drawCharacters(); // 你自己的精灵,或者自行绘制到 frame.color 中
fx.draw(frame, "front");
composite(frame, img.data, background); // 颜色覆盖在背景之上加上辉光;或为 null 表示透明
ctx.putImageData(img, 0, 0); // 然后用 image-rendering: pixelated 缩放画布
if (fx.done()) removeIt(); // 一次性特效自行结束;fx.stop() 使循环特效淡出
多个特效可以共享同一个 frame。在 WebGL 引擎中,每帧将合成后的 RGBA 上传到纹理,或者一次性将特效渲染成精灵表(见下文)并像任何其他动画一样播放。
任何引擎(Godot、Unity、GameMaker、Defold、LÖVE、Bevy、Construct):导出精灵表。
node build-tools/tools/render.mjs ice/frost-nova --sheet 会写入 records/ice/frost-nova/frost-nova.png(网格中的透明帧)和 frost-nova.json(Aseprite 样式的帧,因此 Phaser 的图集加载器、Godot 和 Unity 的 Aseprite 导入器以及大多数工具都能读取;meta.pokuFx 包含 fps、循环、帧大小、列数和轴点)。将轴点设置为 meta.pokuFx.pivot(特效的原点,例如脚部),使用最近邻过滤且无压缩进行导入,并以 meta.pokuFx.fps 播放。辉光会作为带有 alpha 的颜色烘焙到表单中,在暗场景中读取为叠加效果;对于亮场景,渲染一个换色版本或将特效保留在暗图层上。
对于整个库:node build-tools/tools/render.mjs <category> --sheet 会处理整个类别。
一次攻击需要背后有实体。 单独的特效看起来像贴纸。附带角色的特效携带有 act:角色如何蓄力、何时停滞、目标如何反应。无论游戏如何构建,都可以使用它:
- 使用内置角色:
createAct(slash, { x, y })代替createFx。act.update(dt)、act.draw(frame),并通过act.shake进行震动。在停滞期间它会自行保持静止。node build-tools/tools/act.mjs <id> --sheet将整个内容烘焙成精灵表。 - 使用游戏自己的角色:读取时间信息
slash.act或表单 JSON 中的meta.pokuFx.act(包含windup、recovery、hits及其t和freeze)。在特效之前windup秒播放角色的攻击动画,并在每次命中时停止更新所有内容(特效和角色),持续freeze秒。宿主端命中停滞可作用于任何特效,无论是否包含 act。
src/fx/moves/ 包含从特效串联而成的完整攻击,从蓄力到恢复:当有人要求一个招式(而非特效)时,从此处开始。
3. 创建一个新的特效
首先阅读 docs/AUTHORING.md:它是契约(meta、纯特效的 draw(p, t, o) 或模拟特效的 create(o)、局部坐标、无缝循环、空结束)、工具集、绘制器 API 和质量标准。同时阅读 docs/QUALITY.md。将 shadow/spatial-severance 视为干净曲线、精炼粒子的参考,而非强加于所有特效的风格。新的特效应在适当的地方使用共享的 ribbon、轨迹拖尾、包络线和路径光照辅助工具。保持像素调色板,检查原生尺寸的轮廓、打击时机、负空间和透明度。自动化测试不能保证艺术质量。
对于带有冲击的特效,还要阅读 docs/IMPACT_INTERACTIONS.md:编写一个接触描述符(时间、局部点、法线、材质),并从中推导出形状特定的响应和可选的场景反馈。审查地面/目标反应、二次碰撞和稳定过程。不要为每种材质都添加相同的冲击环、碎石或屏幕震动。保留减少运动和支持固定轴点透明导出的功能。
然后:
- 用一句话描述并附上美术指导:它是什么、如何运动、它的调色板、它的时间控制。“一个冰霜新星:水晶从脚部向外呈环形爆发,中心有一道白色闪光,碎片旋转飞出,地板保持结霜并逐渐消失。”
- 在库中查找参考:
node build-tools/tools/list.mjs <words>,然后阅读两到三个最接近的特效文件并借用它们的技术(src/core/sim.ts中的Particles和Bits用于火花、烟雾和碎片,p.disc用于半透明体积,cycle用于无缝粒子,tileFbm用于火焰和水的滚动)。以本地库参考作为质量标准;外部参考是可选的,需要网络访问。 - 制作草稿。
node build-tools/tools/new.mjs <category>/<name>(为循环特效添加--loop)会生成一个可工作的文件。当方向未定时,编写 3 到 5 个真正不同的草稿(<name>-a.ts..-e.ts),全部渲染(node build-tools/tools/render.mjs "<category>/<name>-*"),并在选择前查看每个联系表。如果用户在场,向他们展示最强的两到三个(--gif可生成可分享的动画)。修改源文件后,在渲染前重新构建。 - 观察、评判、修复。 渲染,打开
records/<id>/contact.png,像一个挑剔的像素艺术家一样评判。修复最糟糕的问题,再次渲染。至少三轮;一个精品需要更多轮次。--all显示每一帧,--mp4以全速显示运动。 - 如果涉及角色,为其设计动作: 添加
export const act(参见docs/AUTHORING.md中的“动作”),包含 t = 0 之前的蓄力、在释放帧上的姿势变化、接触时的停滞和恢复。node build-tools/tools/act.mjs <id>显示连续的 12 fps 步骤:根据这些步骤和--mp4判断运动,而非联系表的样本。 - 检查。
node build-tools/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 秒)、更大的轮廓变化、震动 |
| 打击不同步 | 将攻击键移动到特效自身的常量,而非你目测的时间 |
| 武器握持不佳 | 保持肘部弯曲、剑柄在胸前;挥砍时刀尖滞后于手;手臂约伸展 15 像素且不要拉伸,因此身体需要迈步 |
| 手臂交叉或姿势扁平 | 他面向我们的四分之三侧:张开的双臂时近侧手向左(fx < 0),远侧手向右,配合 turn: 1;yaw 真正地转他 |
定向特效面朝右,地面特效站在 y = 0 上,角色特效包裹 o.actor(一个 24 x 38 标准角色的掩码和像素),并且不使用 Math.random。通用主题是可以的;切勿重绘特定游戏的精灵、角色或徽标。
4. 用原生代码代替 JS
如果游戏无法运行 JS 且精灵表不够用(需要跟随移动目标的特效,或需要在运行时进行每个实例颜色调整),则移植该特效。纯特效是时间的函数;模拟特效则通过 src/core/sim.ts 推动粒子。保留双缓冲概念、用于抖动 alpha 的 4x4 Bayer 阈值和调色板渐变查找。并排渲染 JS 原版和你的移植版本以检查它们是否匹配。
核心、所有特效、图库和 CLI 均为 TypeScript 源码。使用前构建;创建或更改 .ts 特效后,在渲染前重新构建。图库和 CLI 搜索支持韩语和英语;韩语文本回退到系统字体。对于引擎原生工作,请参阅 docs/NATIVE_MIGRATION.md;不要声称存在原生运行时。
分享结果
当用户请求公开分享时,使用本地检出目录并运行 npm run build,然后运行 npm run share -- <category>/<effect>。该命令会在新的 records/share/ 文件夹中渲染一个透明 PNG 及其 Poku JSON,验证当前站点大小和动画限制,并打印绝对文件路径以及分享页面。它不会发布或登录。
打开 https://poku-pixel-fx.stankjedi.chatgpt.site/shared,如果需要则使用 ChatGPT 登录,并按照页面上传流程操作。在分享表单中一起选择匹配的 PNG 和 JSON,填写任何必需的标题和标签,上传器确认权利声明后提交。对于多个作品,批量部分接受匹配的 PNG 和 JSON 文件名。使用用户请求的艺术作品,并遵守浏览器的上传和确认规则。切勿伪造身份标头、获取或复制凭据,或在未经用户确认的情况下断言用户的合法权利。在声称发布前,检查图库中的成功消息和生成的条目。该站点可能会强制实施每账户配额。重新分发软件时保留 LICENSE、NOTICE 以及第三方版权和许可声明。