¿Qué hace poku-pixel-fx?
POKU Pixel FX es un fork/derivado de código abierto basado en TypeScript y localizado al coreano de PixelFX de Patch, mantenido como un repositorio independiente sin enlace de red-fork de GitHub. La licencia MIT original acredita a Patch y Hugo Duprez; conserva los avisos de copyright y atribución en LICENCIA y AVISOS.md.
Requiere Node.js 18 o superior; ffmpeg es opcional para vistas previas en GIF y MP4.
Efectos de arte pixelado como código. Cada efecto es un archivo, src/fx/<categoría>/<nombre>.ts, que dibuja en dos búferes:
color (píxeles: opacos, interpolados o verdaderamente translúcidos) y luz (brillo aditivo). Sin imágenes, por lo que un efecto
se puede reproducir en vivo, recolorizar, reflejar, resemillar y renderizar a una hoja de sprites para cualquier motor.
El método es de Hugo Duprez (Cómo hacer efectos de arte pixelado (buenos) con Claude): el código es arcilla, confía en tus ojos, alimenta tus referencias. Las indicaciones de una sola vez producen efectos mediocres. Los borradores que renderizas, miras y refinas hacen los buenos.
Antes de nada
- Trabaja en una copia de Poku Pixel FX que contenga
package.jsonytools/render.mts. Si no existe, obtén la librería pública en el proyecto o espacio de trabajo elegido por el usuario:git clone https://github.com/Stankjedi/poku-pixel-fx.git. El archivo del skill por sí solo no contiene la librería de efectos. Nunca uses la ruta específica de la máquina de otra persona. Instala las dependencias de la copia connpm cicuando sea necesario; no lo repitas si ya está instalado. - Ejecuta
npm run buildantes de usar las herramientas o la galería; el compilador emite módulos de tiempo de ejecución abuild/y herramientas CLI abuild-tools/. - Comprueba que funciona:
node build-tools/tools/render.mjs fire/torchescriberecords/fire/torch/contact.png. Abre ese PNG con tu herramienta de lectura de imágenes. Esa hoja de contactos es como verás todos los efectos a partir de ahora.
1. Busca un efecto existente primero
node build-tools/tools/list.mjs <palabras> busca en ids, nombres, etiquetas y descripciones (node build-tools/tools/list.mjs frost,
node build-tools/tools/list.mjs slash loop). docs/CATALOG.md lista todo por categoría. Renderiza los candidatos y
míralos antes de elegir. La mayoría de las solicitudes son un efecto existente con diferentes opciones:
palette: la rampa principal, de oscuro a brillante, como cadenas hexadecimales. Cualquier rampaPALensrc/core/color.ts(fuego ascua lava humo polvo hielo agua eléctrico voltio veneno sagrado curar arcanos sombra sangre tierra piedra oro hoja madera metal hueso neón cyber matrix caramelo noche) o la tuya propia. Un fuego azul es{"palette": PAL.ice}.seedpara una versión diferente pero equivalente;flippara mirar a la izquierda;anglepara rotar;light(0..1+) para la fuerza del brillo; más los propios controles de cada efecto en susmeta.options(tamaño, cuenta, radio, texto, altura...).- Prueba opciones sin editar código:
node build-tools/tools/render.mjs fire/torch --opts '{"palette":["#102","#215","#43a","#8cf","#fff"]}'.
2. Ponlo en el juego
Juegos en Canvas o WebGL en JS o TS (canvas plano, Phaser, PixiJS, Kaplay, three.js): usa el código directamente. No
tiene dependencias; copia src/core y los archivos de efecto que necesites, o depende del repositorio.
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); // la resolución de píxeles del juego; ox, oy lo desplazan con la cámara
const img = new ImageData(320, 180);
const fx = createFx(frostNova, { x: hero.x, y: hero.y, flip: hero.facing < 0 });
// cada tick
fx.update(dt);
clearFrame(frame);
fx.draw(frame, "back"); // lo que va detrás de los personajes
drawCharacters(); // tus propios sprites, o dibújalos tú mismo en frame.color
fx.draw(frame, "front");
composite(frame, img.data, background); // color sobre el fondo más luz; o null para transparente
ctx.putImageData(img, 0, 0); // luego escala el canvas hacia arriba con image-rendering: pixelated
if (fx.done()) removeIt(); // los de un solo uso terminan solos; fx.stop() desvanece un bucle
Varios efectos pueden compartir un solo frame. En un motor WebGL, sube el RGBA compuesto a una textura cada frame, o renderiza el efecto a una hoja de sprites una vez (abajo) y reprodúcelo como cualquier otra animación.
Cualquier motor (Godot, Unity, GameMaker, Defold, LÖVE, Bevy, Construct): exporta hojas de sprites.
node build-tools/tools/render.mjs ice/frost-nova --sheet escribe records/ice/frost-nova/frost-nova.png (frames transparentes
en una cuadrícula) y frost-nova.json (frames estilo Aseprite, por lo que el cargador de atlas de Phaser, los importadores de Aseprite
de Godot y Unity y la mayoría de las herramientas lo leen; meta.pokuFx tiene fps, bucle, tamaño de frame, columnas y el pivote). Establece el
pivote en meta.pokuFx.pivot (el origen del efecto, p. ej., los pies), importa con filtro de vecino más cercano y sin
compresión, y reproduce a meta.pokuFx.fps. El brillo está horneado en la hoja como color con alfa, que se lee como
aditivo sobre escenas oscuras; para escenas brillantes, renderiza una versión recoloreada o mantén el efecto en una capa oscura.
Para la librería completa: node build-tools/tools/render.mjs <categoría> --sheet hace una categoría entera.
Un golpe necesita un cuerpo detrás. Un efecto solo parece una pegatina. Los efectos con un personaje llevan un act: cuando el cuerpo se
prepara, cuándo congelar, cómo reacciona el objetivo. Úsalo como sea que esté construido el juego:
- Con el personaje estándar:
createAct(slash, { x, y })en lugar decreateFx.act.update(dt),act.draw(frame), y lanza la imagen conact.shake. Se mantiene quieto solo durante una congelación.node build-tools/tools/act.mjs <id> --sheethornea todo en una hoja de sprites. - Con el personaje propio del juego: lee la sincronización,
slash.actometa.pokuFx.acten el JSON de la hoja (windup,recovery,hitscontyfreeze). Reproduce la animación de ataque del personajewindupsegundos antes del efecto, y en cada golpe detén la actualización de todo, efecto y personajes, durantefreezesegundos. La detención de golpe del lado del anfitrión funciona en cualquier efecto, con o sin act.
src/fx/moves/ tiene ataques completos encadenados a partir de los efectos, desde la preparación hasta la recuperación: empieza ahí cuando alguien pide un movimiento, no un efecto.
3. Crea uno nuevo
Lee docs/AUTHORING.md primero: es el contrato (meta, draw(p, t, o) para efectos puros o create(o) para los
simulados, coordenadas locales, bucles sin costuras, final vacío), el kit de herramientas, la API del pintor y el estándar de calidad.
Lee también docs/QUALITY.md. Trata shadow/spatial-severance como la referencia de curva limpia y partículas refinadas,
no como un estilo que imponer a todos los efectos. Los efectos nuevos deben usar los ayudantes compartidos de cinta, estela de trayectoria, envolvente
y iluminación de trayectoria cuando sea apropiado. Mantén la paleta de píxeles e inspecciona las siluetas a tamaño nativo,
la sincronización del impacto, el espacio negativo y la transparencia. Las pruebas automatizadas no garantizan la calidad artística.
Para efectos que soportan impacto, lee también docs/IMPACT_INTERACTIONS.md: crea un descriptor de contacto
(tiempo, punto local, normal, material), y deriva de él la respuesta específica de la forma y la retroalimentación opcional de la escena.
Revisa la reacción del suelo/objetivo, las colisiones secundarias y el asentamiento. No añadas el mismo anillo de impacto,
escombros de piedra o sacudida de pantalla a cada material. Preserva el movimiento reducido y las exportaciones transparentes
de pivote fijo.
Luego:
- Dilo en una línea con dirección artística: qué es, cómo se mueve, su paleta, su sincronización. "Una nova de hielo: cristales que brotan en un anillo desde los pies hacia afuera, un destello blanco en el centro, fragmentos que se desprenden, el suelo permanece helado y se desvanece."
- Encuentra referencias en la librería:
node build-tools/tools/list.mjs <palabras>, luego lee los dos o tres archivos de efecto más cercanos y toma prestadas sus técnicas (ParticlesyBitsensrc/core/sim.tspara chispas, humo y escombros,p.discpara volúmenes translúcidos,cyclepara partículas sin costuras, desplazamientostileFbmpara llamas y agua). Usa las referencias de la librería local como estándar de calidad; las referencias externas son opcionales y requieren acceso a la red. - Boceto.
node build-tools/tools/new.mjs <categoría>/<nombre>(añade--looppara un bucle) da un archivo funcional. Cuando la dirección sea abierta, escribe de 3 a 5 bocetos genuinamente diferentes (<nombre>-a.ts..-e.ts), renderízalos todos (node build-tools/tools/render.mjs "<categoría>/<nombre>-*") y mira cada hoja de contactos antes de elegir. Muestra al usuario los dos o tres más fuertes si están cerca (--gifhace animaciones para compartir). Reconstruye después de cambiar los archivos fuente antes de renderizar. - Mira, juzga, arregla. Renderiza, abre
records/<id>/contact.png, y juzga como un artista de píxeles exigente. Arregla lo peor, renderiza de nuevo. Mínimo tres rondas; una obra maestra lleva más.--allmuestra cada frame,--mp4muestra el movimiento a máxima velocidad. - Actúalo si está involucrado un personaje: añade
export const act(ver "Acts" endocs/AUTHORING.md), con una preparación antes de t = 0, un cambio de pose en el frame de liberación, una congelación en el contacto y una recuperación.node build-tools/tools/act.mjs <id>muestra pasos consecutivos de 12 fps: juzga el movimiento a partir de esos y de--mp4, no de una muestra de la hoja de contactos. - Verifica.
node build-tools/tools/check.mjs <id>detecta dibujo fuera del canvas, efectos de un solo uso que no terminan vacíos, costuras de bucle, aleatoriedad sin semilla y frames lentos, y en un act: claves fuera de orden, campos de pose desconocidos y manos que teletransportan. Arregla hasta que pase limpio. Elimina los bocetos que no conservaste.
Qué buscar, y la solución habitual:
| ves | arreglo |
|---|---|
| se lee como puré a 1x | menos colores, una silueta clara, un punto focal, formas más grandes |
| motas: píxeles de ruido solitarios dentro de formas | umbral de ruido menor, cuantifica con at(), sin ruido en formas pequeñas |
| flotante, sin impacto | rápido de entrada, lento de salida (ease.outQuart/outExpo), un frame de héroe blanco de 1 a 2, tiempo total más corto |
| rígido o mecánico | varía cada partícula (tamaño, velocidad, retardo, vida), añade movimiento secundario (chispas, humo, escombros) |
| deslavado | menos brillo (k 0.2 a 0.5), pasos de borde más oscuros, guarda el blanco solo para el núcleo más caliente |
| plano | luz desde un lado: más brillante arriba a la izquierda, paso más oscuro abajo a la derecha; un paso de rampa más oscuro en la base |
| degradados suaves, aspecto vectorial | pasos de rampa duros en color; suavidad solo en luz y en humo translúcido |
| un patrón de tablero de ajedrez donde debería haber humo | partículas SMOKE, VAPOUR o DUST, o p.disc: verdaderamente translúcido, iluminado en la parte superior |
| costura cuando un bucle se cierra | cycle, loopNoise(phase), desplazamientos de celda completa tileNoise, sin(phase * TAU * n) |
| un efecto de un solo uso que desaparece de golpe | déjalo encoger, difuminar o desvanecerse antes de t = duración |
| un gran efecto en un personaje muerto | dale un act: preparación, pose de liberación, congelación en contacto, un objetivo que reacciona, recuperación |
| el act se siente sin peso | una preparación en dirección opuesta al golpe, una congelación más larga (hasta 0.2 s), un cambio de silueta más grande, sacudida |
| el golpe aterriza fuera de sincronía | mueve la clave de golpe a la propia constante del efecto, no a un tiempo que calculaste a ojo |
| sostiene el arma mal | mantén una flexión en el codo, astas delante del pecho; en un balanceo la hoja se retrasa respecto a la mano; los brazos alcanzan unos 15 px y no se estiran, por lo que mueve el cuerpo |
| sus brazos se cruzan o la pose se ve plana | mira hacia tres cuartos hacia nosotros: para brazos abiertos la mano cercana va a la izquierda (fx < 0), la lejana a la derecha, con turn: 1; yaw realmente lo gira |
Los efectos direccionales miran a la derecha, los efectos de suelo se paran en y = 0, los efectos de actor envuelven o.actor (la máscara y píxeles de un
personaje estándar de 24 x 38), y nada usa Math.random. Los motivos genéricos están bien; nunca recrees sprites, personajes o logotipos de un juego específico.
4. Código nativo en lugar de JS
Si el juego no puede ejecutar JS y una hoja de sprites no es suficiente (un efecto que sigue un objetivo en movimiento, o necesita
colores por instancia en tiempo de ejecución), porta el efecto. Los efectos puros son una función del tiempo; los simulados avanzan las partículas en
src/core/sim.ts. Mantén la idea de dos búferes, el umbral Bayer de 4x4 para el alfa interpolado y las búsquedas de rampa de paleta.
Renderiza el original en JS y tu portabilidad lado a lado para verificar que coinciden.
El núcleo, todos los efectos, la galería y la CLI son fuentes TypeScript. Construye antes de usar; después de crear o cambiar un efecto .ts, reconstruye antes de renderizar. La galería y la búsqueda CLI admiten coreano e inglés; el texto en coreano recurre a una fuente del sistema. Para trabajo nativo del motor consulta docs/NATIVE_MIGRATION.md; no afirmes que existe un tiempo de ejecución nativo.
Compartir un resultado
Cuando el usuario solicite compartir públicamente, usa la copia local y ejecuta npm run build seguido de npm run share -- <categoría>/<efecto>. El comando renderiza un PNG transparente y su JSON de Poku en una nueva carpeta records/share/, valida los límites actuales de tamaño del sitio y de animación, e imprime las rutas de archivo absolutas y la página de compartir. No publica ni inicia sesión.
Abre https://poku-pixel-fx.stankjedi.chatgpt.site/shared, inicia sesión con ChatGPT si es necesario, y sigue el flujo de carga de la página. Selecciona el PNG y el JSON correspondientes juntos en el formulario de compartir, completa cualquier título y etiquetas requeridos, y envía después de que el cargador confirme la declaración de derechos. Para múltiples trabajos, la sección de lote acepta nombres de archivo PNG y JSON coincidentes. Usa la obra de arte solicitada por el usuario y cumple con las reglas de carga y confirmación del navegador. Nunca fabriques cabeceras de identidad, obtengas ni copies credenciales, ni afirmes los derechos legales del usuario sin su confirmación. Verifica la galería para ver un mensaje de éxito y la entrada resultante antes de afirmar una publicación. El sitio puede imponer cuotas por cuenta. Conserva LICENCIA, AVISOS y los avisos de derechos de autor y permiso de terceros al redistribuir el software.