Que fait poku-pixel-fx ?
POKU Pixel FX est un fork/derivé open source en TypeScript, localisé en coréen, de PixelFX par Patch. Il est maintenu comme un dépôt séparé, sans lien de fork réseau GitHub. La licence MIT originale crédite Patch et Hugo Duprez ; conservez les mentions de droit d'auteur et d'attribution dans LICENSE et NOTICE.md.
Nécessite Node.js 18 ou version ultérieure ; ffmpeg est optionnel pour les aperçus GIF et MP4.
Des effets pixel art sous forme de code. Chaque effet est un fichier, src/fx/<catégorie>/<nom>.ts, qui dessine dans deux tampons :
couleur (pixels opaques, tramés ou vraiment translucides) et lumière (lueur additive). Aucune image, donc un effet
peut être joué en direct, recoloré, mis en miroir, réensemencé et rendu en feuille de sprites pour n'importe quel moteur.
La méthode est celle d'Hugo Duprez (Comment créer de bons effets pixel art avec Claude) : le code est de l'argile, faites confiance à vos yeux, nourrissez-vous de références. Les requêtes uniques produisent des effets médiocres. Les brouillons que vous rendez, observez et affinez donnent de bons résultats.
Avant toute chose
- Travaillez dans une copie de travail de Poku Pixel FX contenant
package.jsonettools/render.mts. Si elle n'existe pas, récupérez la bibliothèque publique dans le projet ou espace de travail choisi par l'utilisateur :git clone https://github.com/Stankjedi/poku-pixel-fx.git. Le fichier de compétence seul ne contient pas la bibliothèque d'effets. N'utilisez jamais le chemin d'une autre personne spécifique à sa machine. Installez les dépendances de la copie avecnpm cisi nécessaire ; ne le répétez pas si déjà fait. - Lancez
npm run buildavant d'utiliser les outils ou la galerie ; le compilateur émet les modules d'exécution dansbuild/et les outils CLI dansbuild-tools/. - Vérifiez que ça fonctionne :
node build-tools/tools/render.mjs fire/torchécritrecords/fire/torch/contact.png. Ouvrez ce PNG avec votre outil de lecture d'images. Cette planche contact est désormais la façon dont vous verrez chaque effet.
1. Cherchez d'abord un effet existant
node build-tools/tools/list.mjs <mots> cherche dans les ids, noms, tags et descriptions (node build-tools/tools/list.mjs frost,
node build-tools/tools/list.mjs slash loop). docs/CATALOG.md liste tout par catégorie. Rendez les candidats et regardez-les avant de choisir. La plupart des demandes sont un effet existant avec des options différentes :
palette: la rampe principale, du sombre au clair, sous forme de chaînes hexadécimales. Toute rampePALdanssrc/core/color.ts(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) ou la vôtre. Un feu bleu est{"palette": PAL.ice}.seedpour une version différente mais équivalente ;flippour orienter à gauche ;anglepour tourner ;light(0..1+) pour l'intensité de la lueur ; plus les propres boutons de chaque effet dansmeta.options(taille, compte, rayon, texte, hauteur...).- Essayez des options sans modifier le code :
node build-tools/tools/render.mjs fire/torch --opts '{"palette":["#102","#215","#43a","#8cf","#fff"]}'.
2. Mettez-le dans le jeu
Jeux Canvas ou WebGL en JS ou TS (canvas simple, Phaser, PixiJS, Kaplay, three.js) : utilisez le code directement. Il n'a pas de dépendances ; copiez src/core et les fichiers d'effets dont vous avez besoin, ou dépendez du dépôt.
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 résolution pixel du jeu ; ox, oy le font défiler avec la caméra
const img = new ImageData(320, 180);
const fx = createFx(frostNova, { x: hero.x, y: hero.y, flip: hero.facing < 0 });
// à chaque tic
fx.update(dt);
clearFrame(frame);
fx.draw(frame, "back"); // ce qui va derrière les personnages
drawCharacters(); // vos propres sprites, ou dessinez-les dans frame.color vous-même
fx.draw(frame, "front");
composite(frame, img.data, background); // couleur sur l'arrière-plan plus lumière ; ou null pour transparent
ctx.putImageData(img, 0, 0); // puis mettez l'échelle du canvas avec image-rendering: pixelated
if (fx.done()) removeIt(); // les one-shots se terminent d'eux-mêmes ; fx.stop() atténue une boucle
Plusieurs effets peuvent partager une même trame. Dans un moteur WebGL, téléchargez le RGBA composite dans une texture à chaque image, ou rendez l'effet en feuille de sprites une fois (ci-dessous) et jouez-le comme n'importe quelle autre animation.
Tout moteur (Godot, Unity, GameMaker, Defold, LÖVE, Bevy, Construct) : exportez des feuilles de sprites.
node build-tools/tools/render.mjs ice/frost-nova --sheet écrit records/ice/frost-nova/frost-nova.png (images transparentes dans une grille) et frost-nova.json (images de style Aseprite, donc le chargeur d'atlas de Phaser, les importateurs Aseprite de Godot et Unity et la plupart des outils le lisent ; meta.pokuFx contient fps, boucle, taille d'image, colonnes et le pivot). Définissez le pivot sur meta.pokuFx.pivot (l'origine de l'effet, par exemple les pieds), importez avec un filtrage au plus proche voisin et sans compression, et jouez à meta.pokuFx.fps. La lueur est intégrée dans la feuille sous forme de couleur avec alpha, qui se lit comme additive sur les scènes sombres ; pour les scènes claires, rendez une version recolorée ou gardez l'effet sur une couche sombre.
Pour la bibliothèque complète : node build-tools/tools/render.mjs <catégorie> --sheet produit toute une catégorie.
Un coup a besoin d'un corps derrière lui. Un effet seul ressemble à un autocollant. Les effets avec un personnage portent un act : quand le corps se prépare, quand geler, comment la cible réagit. Utilisez-le selon la construction du jeu :
- Avec le personnage standard :
createAct(slash, { x, y })au lieu decreateFx.act.update(dt),act.draw(frame), et jetez l'image paract.shake. Il se fige tout seul lors d'un gel.node build-tools/tools/act.mjs <id> --sheetintègre le tout dans une feuille de sprites. - Avec votre propre personnage : lisez le timing,
slash.actoumeta.pokuFx.actdans le JSON d'une feuille (windup,recovery,hitsavectetfreeze). Jouez l'animation d'attaque du personnagewindupsecondes avant l'effet, et à chaque coup, arrêtez tout, effet et personnages, pendantfreezesecondes. Le hit-stop côté hôte fonctionne sur n'importe quel effet, avec ou sans act.
src/fx/moves/ contient des attaques complètes enchaînées à partir des effets, de la préparation à la récupération : commencez là quand on demande un mouvement, pas un effet.
3. Créez-en un nouveau
Lisez d'abord docs/AUTHORING.md : c'est le contrat (meta, draw(p, t, o) pour les effets purs ou create(o) pour les simulés, coordonnées locales, boucles sans couture, terminaison vide), la boîte à outils, l'API de peinture et la barre de qualité. Lisez aussi docs/QUALITY.md. Considérez shadow/spatial-severance comme la référence pour les courbes nettes et les particules raffinées, pas un style à imposer à tous les effets. Les nouveaux effets devraient utiliser les aides partagées (ruban, traînée de trajectoire, enveloppe, éclairage de chemin) quand c'est approprié. Gardez la palette pixel et inspectez les silhouettes en taille native, le timing d'impact, l'espace négatif et la transparence. Les tests automatisés ne garantissent pas la qualité artistique. Pour les effets porteurs d'impact, lisez aussi docs/IMPACT_INTERACTIONS.md : décrivez un descripteur de contact (temps, point local, normale, matériau), et dérivez-en la réponse spécifique à la forme et les retours de scène optionnels. Examinez la réaction du sol/de la cible, les collisions secondaires et le tassement. N'ajoutez pas le même anneau de choc, les mêmes débris de pierre ou le même tremblement d'écran à chaque matériau. Préservez la réduction de mouvement et les exports transparents à pivot fixe.
Ensuite :
- Dites-le en une ligne avec une direction artistique : ce que c'est, comment ça bouge, sa palette, son timing. "Une nova de givre : des cristaux jaillissent en un anneau des pieds vers l'extérieur, un éclair blanc au centre, des éclats tourbillonnent, le sol reste givré et s'estompe."
- Trouvez des références dans la bibliothèque :
node build-tools/tools/list.mjs <mots>, puis lisez les deux ou trois fichiers d'effets les plus proches et empruntez leurs techniques (ParticlesetBitsdanssrc/core/sim.tspour les étincelles, la fumée et les débris,p.discpour les volumes translucides,cyclepour les particules sans couture,tileFbmpour les défilements de flammes et d'eau). Utilisez les références de la bibliothèque locale comme barre de qualité ; les références externes sont optionnelles et nécessitent un accès réseau. - Brouillonnez.
node build-tools/tools/new.mjs <catégorie>/<nom>(ajoutez--looppour une boucle) donne un fichier de travail. Quand la direction est ouverte, écrivez 3 à 5 brouillons vraiment différents (<nom>-a.ts..-e.ts), rendez-les tous (node build-tools/tools/render.mjs "<catégorie>/<nom>-*") et regardez chaque planche contact avant de choisir. Montrez à l'utilisateur les deux ou trois plus forts s'il est présent (--gifcrée des animations à partager). Reconstruisez après avoir modifié les fichiers source avant de rendre. - Regardez, jugez, corrigez. Rendez, ouvrez
records/<id>/contact.png, et jugez comme un pixel artiste exigeant. Corrigez la pire chose, rendez à nouveau. Trois cycles minimum ; une pièce maîtresse en demande plus.--allmontre chaque image,--mp4montre le mouvement à pleine vitesse. - Jouez-le si un personnage est impliqué : ajoutez
export const act(voir "Acts" dansdocs/AUTHORING.md), avec une préparation avant t = 0, un changement de pose sur l'image de lâcher, un gel au contact et une récupération.node build-tools/tools/act.mjs <id>montre les étapes consécutives à 12 fps : jugez le mouvement à partir de celles-ci et de--mp4, pas à partir d'échantillons d'une planche contact. - Vérifiez.
node build-tools/tools/check.mjs <id>détecte le dessin en dehors du canvas, les one-shots qui ne se terminent pas vides, les coutures de boucle, l'aléatoire non ensemencé et les images lentes, et dans un act : les touches dans le désordre, les champs de pose inconnus et les mains qui se téléportent. Corrigez jusqu'à ce que tout passe propre. Supprimez les brouillons que vous n'avez pas gardés.
Ce qu'il faut chercher, et la correction habituelle :
| vous voyez | correction |
|---|---|
| ça ressemble à de la bouillie en 1x | moins de couleurs, une silhouette claire, un point focal, des formes plus grandes |
| mouchetis : pixels de bruit isolés dans les formes | seuil de bruit plus bas, quantifiez avec at(), pas de bruit sur les petites formes |
| flottant, sans punch | rapide dedans, lent dehors (ease.outQuart/outExpo), une image héroïque blanche de 1 à 2 images, durée totale plus courte |
| rigide ou mécanique | variez chaque particule (taille, vitesse, délai, durée de vie), ajoutez un mouvement secondaire (étincelles, fumée, débris) |
| délavé | moins de lueur (k 0.2 à 0.5), bords plus foncés, gardez le blanc pour le seul cœur le plus chaud |
| plat | lumière d'un côté : haut-gauche plus clair, bas-droite plus foncé ; un pas de rampe plus foncé à la base |
| dégradés lisses, aspect vectoriel | pas de rampe durs dans la couleur ; la douceur seulement dans la lumière et la fumée translucide |
| un damier là où la fumée devrait être | particules SMOKE, VAPOUR ou DUST, ou p.disc : vraiment translucides, éclairées par-dessus |
| couture quand une boucle se referme | cycle, loopNoise(phase), défilements tileNoise par cellule entière, sin(phase * TAU * n) |
| un one-shot qui disparaît brusquement | laissez-le rétrécir, se tramer ou s'éloigner avant t = durée |
| un super effet sur un personnage mort | donnez-lui un act : préparation, pose de lâcher, gel au contact, une cible qui réagit, récupération |
| l'act semble sans poids | une préparation dans le sens contraire du coup, un gel plus long (jusqu'à 0.2 s), un plus grand changement de silhouette, secousse |
| le coup arrive hors synchronisation | déplacez la touche de coup dans la constante propre de l'effet, pas dans un temps que vous avez estimé |
| il tient mal l'arme | gardez un pli au coude, les lances devant la poitrine ; lors d'un balancement, la lame retarde sur la main ; les bras atteignent environ 15 px et ne s'étirent pas, donc avancez le corps |
| ses bras se croisent ou la pose est plate | il fait face aux trois quarts vers nous : pour les bras ouverts, la main proche va à gauche (fx < 0), la main éloignée à droite, avec turn: 1 ; yaw le tourne vraiment |
Les effets directionnels font face à droite, les effets au sol se tiennent sur y = 0, les effets d'acteur enveloppent o.actor (le masque et les pixels d'un personnage standard de 24 x 38), et rien n'utilise Math.random. Les motifs génériques sont acceptables ; ne recréez jamais les sprites, personnages ou logos d'un jeu spécifique.
4. Code natif au lieu de JS
Si le jeu ne peut pas exécuter JS et qu'une feuille de sprites ne suffit pas (un effet qui suit une cible mobile, ou qui nécessite des couleurs par instance à l'exécution), portez l'effet. Les effets purs sont une fonction du temps ; les simulés font avancer les particules dans src/core/sim.ts. Gardez l'idée des deux tampons, le seuil de Bayer 4x4 pour l'alpha tramé et les recherches de rampe de palette. Rendez l'original JS et votre portage côte à côte pour vérifier qu'ils correspondent.
Le noyau, tous les effets, la galerie et la CLI sont en TypeScript. Construisez avant utilisation ; après avoir créé ou modifié un effet .ts, reconstruisez avant de rendre. La galerie et la CLI prennent en charge le coréen et l'anglais ; le texte coréen se rabat sur une police système. Pour un travail natif sur moteur, consultez docs/NATIVE_MIGRATION.md ; n'affirmez pas qu'un runtime natif existe.
5. Partager un résultat
Lorsque l'utilisateur demande un partage public, utilisez la copie de travail locale et exécutez npm run build suivi de npm run share -- <catégorie>/<effet>. La commande rend un PNG transparent et son JSON Poku dans un nouveau dossier records/share/, valide la taille actuelle du site et les limites d'animation, et affiche les chemins de fichiers absolus ainsi que la page de partage. Elle ne publie ni ne connecte.
Ouvrez https://poku-pixel-fx.stankjedi.chatgpt.site/shared, connectez-vous avec ChatGPT si nécessaire, et suivez le flux de téléchargement de la page. Sélectionnez le PNG et le JSON correspondants ensemble dans le formulaire de partage, remplissez le titre et les tags requis, et soumettez après que le téléchargeur confirme la déclaration de droits. Pour plusieurs œuvres, la section de lot accepte les noms de fichiers PNG et JSON correspondants. Utilisez l'œuvre demandée par l'utilisateur et respectez les règles de téléchargement et de confirmation du navigateur. Ne fabriquez jamais d'en-têtes d'identité, n'obtenez ni ne copiez d'identifiants, et n'affirmez pas les droits légaux de l'utilisateur sans sa confirmation. Vérifiez la galerie pour un message de succès et l'entrée résultante avant de revendiquer une publication. Le site peut imposer des quotas par compte. Préservez LICENSE, NOTICE, et les mentions de droit d'auteur et de permission des tiers lors de la redistribution du logiciel.