@pixelvibing/cli 0.53.0 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/pixel-vibing-cli.js
CHANGED
|
@@ -4677,6 +4677,748 @@ function terrainSetPatch(pngs, masks, codec2) {
|
|
|
4677
4677
|
const TERRAIN_CELLS_PER_TILE = [32, 64];
|
|
4678
4678
|
const REFERENCE_ROLES = ["style", "source", "variant"];
|
|
4679
4679
|
const DEFAULT_TERRAIN_CELLS = 32;
|
|
4680
|
+
const VFX_RAMPS = ["arcane", "blood", "electric", "fire", "frost", "holy", "nature", "poison", "shadow", "smoke", "water"];
|
|
4681
|
+
const VFX_PARTS_RANGE = { min: 1, max: 6 };
|
|
4682
|
+
const VFX_COLOURS_RANGE = { min: 2, max: 12 };
|
|
4683
|
+
const VFX_SLIDERS = {
|
|
4684
|
+
size: { min: 0.25, max: 4 },
|
|
4685
|
+
amount: { min: 0.25, max: 3 },
|
|
4686
|
+
speed: { min: 0.25, max: 3 },
|
|
4687
|
+
start: { min: 0, max: 1 },
|
|
4688
|
+
end: { min: 0, max: 1 }
|
|
4689
|
+
};
|
|
4690
|
+
const VFX_PRESETS = [
|
|
4691
|
+
{
|
|
4692
|
+
name: "aura",
|
|
4693
|
+
description: "A flickering aura of power around a standing character: flame tongues behind, sparks rising in front. Seamless loop. Best around a character.",
|
|
4694
|
+
loops: true
|
|
4695
|
+
},
|
|
4696
|
+
{ name: "energy_orb", description: "A crackling ball of energy (projectile head or charge-up) with orbiting sparks. Seamless loop.", loops: true },
|
|
4697
|
+
{ name: "explosion", description: "Fireball explosion: flash, a billowing fire mass that burns out, a shockwave ring, debris. One-shot.", loops: false },
|
|
4698
|
+
{
|
|
4699
|
+
name: "firelight",
|
|
4700
|
+
description: "Warm, flickering firelight from below, as from a campfire at the subject's feet; the far side sinks into the dark. It lights your sprite (shown on a sample asteroid when there is none). Loop.",
|
|
4701
|
+
loops: true
|
|
4702
|
+
},
|
|
4703
|
+
{ name: "flame", description: "A burning flame (campfire, torch, brazier). Seamless loop.", loops: true },
|
|
4704
|
+
{
|
|
4705
|
+
name: "ground_sigil",
|
|
4706
|
+
description: "Summoning circle on the ground, seen from low above, turning, with light rising out of it. Best with a character standing in its middle.",
|
|
4707
|
+
loops: true
|
|
4708
|
+
},
|
|
4709
|
+
{
|
|
4710
|
+
name: "heal_pillar",
|
|
4711
|
+
description: "A soft column of healing light with a ground ring and rising sparkles. Seamless loop; good around a character.",
|
|
4712
|
+
loops: true
|
|
4713
|
+
},
|
|
4714
|
+
{ name: "impact_burst", description: "A hit spark: white flash, rays and a ring punching outward, sparks. One-shot, small.", loops: false },
|
|
4715
|
+
{
|
|
4716
|
+
name: "light_sweep",
|
|
4717
|
+
description: "A light circling the subject: sunlight moving across a rock, a planet turning, an asteroid tumbling past a star. It lights your sprite (shown on a sample asteroid when there is none). Seamless loop.",
|
|
4718
|
+
loops: true
|
|
4719
|
+
},
|
|
4720
|
+
{ name: "lightning_strike", description: "A bolt strikes down from above, flashes, hits the ground with a shockwave and sparks. One-shot.", loops: false },
|
|
4721
|
+
{
|
|
4722
|
+
name: "magic_circle",
|
|
4723
|
+
description: "Front-facing arcane circle: rings, a hexagram and a rune band that turn slowly, twinkling motes. Seamless loop.",
|
|
4724
|
+
loops: true
|
|
4725
|
+
},
|
|
4726
|
+
{ name: "portal", description: "An upright swirling portal: churning core, glowing rim, orbiting motes. Seamless loop.", loops: true },
|
|
4727
|
+
{
|
|
4728
|
+
name: "rim_glow",
|
|
4729
|
+
description: "A pulsing rim of light around the subject's outline, as if something bright stands right behind it (a portal, a halo, an explosion). It lights your sprite (shown on a sample asteroid when there is none). Seamless loop.",
|
|
4730
|
+
loops: true
|
|
4731
|
+
},
|
|
4732
|
+
{
|
|
4733
|
+
name: "shield_bubble",
|
|
4734
|
+
description: "A protective bubble: shimmering rim, glints running round it. Seamless loop. Best around a character.",
|
|
4735
|
+
loops: true
|
|
4736
|
+
},
|
|
4737
|
+
{
|
|
4738
|
+
name: "shockwave",
|
|
4739
|
+
description: "A stomp or landing: a ring of force racing out along the ground, kicking up dust. One-shot, seen from low above.",
|
|
4740
|
+
loops: false
|
|
4741
|
+
},
|
|
4742
|
+
{ name: "slash_arc", description: "A sword slash: a crescent that sweeps open, then fades, with a few glints. One-shot.", loops: false },
|
|
4743
|
+
{ name: "smoke_puff", description: "A puff of smoke that billows up and thins away. One-shot.", loops: false }
|
|
4744
|
+
];
|
|
4745
|
+
const VFX_PARTS = [
|
|
4746
|
+
{
|
|
4747
|
+
name: "alert_pop",
|
|
4748
|
+
description: "A red ! pops up above a character's head with a bounce and burst lines, holds, then vanishes: spotted, surprised, warning.",
|
|
4749
|
+
loops: false,
|
|
4750
|
+
tags: ["alert", "exclamation", "ui", "surprise", "warning", "icon"]
|
|
4751
|
+
},
|
|
4752
|
+
{
|
|
4753
|
+
name: "aura_flames",
|
|
4754
|
+
description: "Flickering tongues of power rising behind a standing character, a ring at the feet, sparks in front.",
|
|
4755
|
+
loops: true,
|
|
4756
|
+
tags: ["aura", "power", "buff", "flames", "charge", "rage"]
|
|
4757
|
+
},
|
|
4758
|
+
{
|
|
4759
|
+
name: "blaster_bolt",
|
|
4760
|
+
description: "A hot capsule of energy with a white core and speed lines behind, flying right (+x): laser, plasma or blaster shots.",
|
|
4761
|
+
loops: true,
|
|
4762
|
+
tags: ["projectile", "laser", "blaster", "energy", "shot", "bolt"]
|
|
4763
|
+
},
|
|
4764
|
+
{
|
|
4765
|
+
name: "blood_splat",
|
|
4766
|
+
description: "A red splat on the hit point with droplets spraying out and falling. Stylised gore; recolour for green ichor or slime.",
|
|
4767
|
+
loops: false,
|
|
4768
|
+
tags: ["blood", "hit", "gore", "splatter", "impact", "droplets"]
|
|
4769
|
+
},
|
|
4770
|
+
{
|
|
4771
|
+
name: "bolt_strike",
|
|
4772
|
+
description: "A bolt strikes down from above onto the anchor, flashes, a shockwave and sparks where it hits.",
|
|
4773
|
+
loops: false,
|
|
4774
|
+
tags: ["lightning", "electric", "bolt", "storm", "strike", "thunder"]
|
|
4775
|
+
},
|
|
4776
|
+
{
|
|
4777
|
+
name: "breath_cone",
|
|
4778
|
+
description: "A billowing cone of flame and sparks pouring right (+x) from the anchor: fire breath, flamethrower; frost or poison gas in other colours.",
|
|
4779
|
+
loops: true,
|
|
4780
|
+
tags: ["breath", "cone", "flamethrower", "spray", "fire", "gas"]
|
|
4781
|
+
},
|
|
4782
|
+
{
|
|
4783
|
+
name: "bubble_shield",
|
|
4784
|
+
description: "A see-through dithered bubble around a character: bright rim, a shine highlight, glints running round: shield, barrier, protect.",
|
|
4785
|
+
loops: true,
|
|
4786
|
+
tags: ["shield", "bubble", "barrier", "protect", "buff"]
|
|
4787
|
+
},
|
|
4788
|
+
{
|
|
4789
|
+
name: "bubbles_rise",
|
|
4790
|
+
description: "Round bubbles of a few sizes rising and wobbling up from the ground: underwater, a bubbling pool, potions, drowning.",
|
|
4791
|
+
loops: true,
|
|
4792
|
+
tags: ["bubbles", "water", "underwater", "rising", "ambient", "potion"]
|
|
4793
|
+
},
|
|
4794
|
+
{
|
|
4795
|
+
name: "buff_arrows",
|
|
4796
|
+
description: "Up-arrows rising from the feet behind a character and fading out: a stat buff, power-up, attack or speed boost.",
|
|
4797
|
+
loops: true,
|
|
4798
|
+
tags: ["buff", "arrows", "status", "powerup", "rising"]
|
|
4799
|
+
},
|
|
4800
|
+
{
|
|
4801
|
+
name: "burn_status",
|
|
4802
|
+
description: "Small flames licking up around and over a character, embers and a hot rim on the sprite: on fire, burn damage over time.",
|
|
4803
|
+
loops: true,
|
|
4804
|
+
tags: ["burn", "fire", "status", "flames", "dot"]
|
|
4805
|
+
},
|
|
4806
|
+
{
|
|
4807
|
+
name: "burning_edge",
|
|
4808
|
+
description: "Sparks flickering up off the sprite's whole outline in a loop: on fire, powered up, cursed, overheating.",
|
|
4809
|
+
loops: true,
|
|
4810
|
+
tags: ["outline", "burn", "aura", "sparks", "loop"]
|
|
4811
|
+
},
|
|
4812
|
+
{
|
|
4813
|
+
name: "campfire",
|
|
4814
|
+
description: "A drawn campfire: five tongues from one hot bed, fanning out and flickering, a few sparks, lighting the scene.",
|
|
4815
|
+
loops: true,
|
|
4816
|
+
tags: ["fire", "campfire", "bonfire", "camp", "loop"]
|
|
4817
|
+
},
|
|
4818
|
+
{
|
|
4819
|
+
name: "candle_flame",
|
|
4820
|
+
description: "A small calm drawn teardrop flame that sways a little, lighting the sprite: candles, lanterns, wicks, a match.",
|
|
4821
|
+
loops: true,
|
|
4822
|
+
tags: ["fire", "candle", "flame", "light", "loop"]
|
|
4823
|
+
},
|
|
4824
|
+
{
|
|
4825
|
+
name: "cartoon_boom",
|
|
4826
|
+
description: "A drawn cartoon explosion: a hot flash, lobed fire clouds thrown out and cooling, then smoke. Bombs, barrels, crits.",
|
|
4827
|
+
loops: false,
|
|
4828
|
+
tags: ["explosion", "fire", "cartoon", "boom", "impact"]
|
|
4829
|
+
},
|
|
4830
|
+
{
|
|
4831
|
+
name: "charge_up",
|
|
4832
|
+
description: "Motes of energy swirling in from all round and gathering at one point, a glow swelling there. Charging a spell.",
|
|
4833
|
+
loops: false,
|
|
4834
|
+
tags: ["charge", "gather", "energy", "magic", "converge"]
|
|
4835
|
+
},
|
|
4836
|
+
{
|
|
4837
|
+
name: "charm_hearts",
|
|
4838
|
+
description: "Three small pink hearts circling the head evenly, passing in front and behind, with twinkles: charmed, infatuated, love status.",
|
|
4839
|
+
loops: true,
|
|
4840
|
+
tags: ["charm", "hearts", "love", "status", "orbit"]
|
|
4841
|
+
},
|
|
4842
|
+
{
|
|
4843
|
+
name: "claw_marks",
|
|
4844
|
+
description: "Three parallel claw scratches ripping diagonally across the target, then crumbling away. Beast attacks, rakes, scratches.",
|
|
4845
|
+
loops: false,
|
|
4846
|
+
tags: ["claw", "scratch", "slash", "beast", "hit", "melee"]
|
|
4847
|
+
},
|
|
4848
|
+
{
|
|
4849
|
+
name: "claw_swipe",
|
|
4850
|
+
description: "Three drawn claw marks raked across in a quick swipe, one a beat after the other, crumbling away. Beasts, monsters.",
|
|
4851
|
+
loops: false,
|
|
4852
|
+
tags: ["claw", "swipe", "beast", "scratch", "hit"]
|
|
4853
|
+
},
|
|
4854
|
+
{
|
|
4855
|
+
name: "cloud_puff",
|
|
4856
|
+
description: "A looping drawn cloud clump wobbling in place, lit from above. Rain or storm clouds over a head, sky decor, dreams.",
|
|
4857
|
+
loops: true,
|
|
4858
|
+
tags: ["cloud", "sky", "weather", "loop", "cartoon"]
|
|
4859
|
+
},
|
|
4860
|
+
{
|
|
4861
|
+
name: "coin_burst",
|
|
4862
|
+
description: "Gold coins pop out of the anchor with a flash ring and glints, arc up and fall away: loot drops, pickups, rewards.",
|
|
4863
|
+
loops: false,
|
|
4864
|
+
tags: ["coins", "loot", "pickup", "gold", "reward", "burst"]
|
|
4865
|
+
},
|
|
4866
|
+
{
|
|
4867
|
+
name: "collect_pop",
|
|
4868
|
+
description: "A quick gold glint and ring popping on the anchor, sparkles drifting up and out: an item, coin or power-up being picked up.",
|
|
4869
|
+
loops: false,
|
|
4870
|
+
tags: ["pickup", "collect", "sparkle", "glint", "item", "reward"]
|
|
4871
|
+
},
|
|
4872
|
+
{
|
|
4873
|
+
name: "comet_trail",
|
|
4874
|
+
description: "A bright head streaking across with a long tapered ribbon tail: comets, magic missiles, wisps; a throw's trail.",
|
|
4875
|
+
loops: false,
|
|
4876
|
+
tags: ["comet", "ribbon", "trail", "missile", "projectile"]
|
|
4877
|
+
},
|
|
4878
|
+
{
|
|
4879
|
+
name: "confetti_pop",
|
|
4880
|
+
description: "A pop of multicoloured paper confetti thrown up from the anchor, flipping as it falls: wins, celebrations, achievements.",
|
|
4881
|
+
loops: false,
|
|
4882
|
+
tags: ["confetti", "celebration", "win", "party", "reward", "burst"]
|
|
4883
|
+
},
|
|
4884
|
+
{
|
|
4885
|
+
name: "crater_dust",
|
|
4886
|
+
description: "A ring of dust clouds billowing out and up from a ground impact, then breaking apart. Heavy landings, slams, boulders.",
|
|
4887
|
+
loops: false,
|
|
4888
|
+
tags: ["dust", "impact", "ground", "slam", "landing", "cloud"]
|
|
4889
|
+
},
|
|
4890
|
+
{
|
|
4891
|
+
name: "curse_skulls",
|
|
4892
|
+
description: "Little pale skulls drifting up around a character's head and fading, with dark motes: cursed, doomed, death mark, hex.",
|
|
4893
|
+
loops: true,
|
|
4894
|
+
tags: ["curse", "skulls", "status", "death", "hex", "debuff"]
|
|
4895
|
+
},
|
|
4896
|
+
{
|
|
4897
|
+
name: "debris_burst",
|
|
4898
|
+
description: "Chunks of rock or wood thrown out of a hit, arcing down under gravity.",
|
|
4899
|
+
loops: false,
|
|
4900
|
+
tags: ["debris", "rocks", "chunks", "impact", "break", "rubble"]
|
|
4901
|
+
},
|
|
4902
|
+
{
|
|
4903
|
+
name: "debuff_arrows",
|
|
4904
|
+
description: "Down-arrows sinking from above the head behind a character and fading: a stat debuff, weaken, slow or armour break.",
|
|
4905
|
+
loops: true,
|
|
4906
|
+
tags: ["debuff", "arrows", "status", "weaken", "curse"]
|
|
4907
|
+
},
|
|
4908
|
+
{
|
|
4909
|
+
name: "dust_kick",
|
|
4910
|
+
description: "Two small dust puffs pushing out sideways along the ground and breaking up: footsteps, landings, skids, dashes.",
|
|
4911
|
+
loops: false,
|
|
4912
|
+
tags: ["dust", "landing", "footstep", "ground", "puff", "jump"]
|
|
4913
|
+
},
|
|
4914
|
+
{
|
|
4915
|
+
name: "dust_puff",
|
|
4916
|
+
description: "A small drawn dust puff kicked up from the ground: footsteps, jumps, an item dropping, a skid start.",
|
|
4917
|
+
loops: false,
|
|
4918
|
+
tags: ["dust", "puff", "ground", "footstep", "cartoon"]
|
|
4919
|
+
},
|
|
4920
|
+
{
|
|
4921
|
+
name: "dust_trail",
|
|
4922
|
+
description: "Dust puffs rolling off the feet and trailing behind (to the left) as they break up. Loop for running, dashing, skidding.",
|
|
4923
|
+
loops: true,
|
|
4924
|
+
tags: ["dust", "trail", "run", "dash", "ground", "loop"]
|
|
4925
|
+
},
|
|
4926
|
+
{
|
|
4927
|
+
name: "ember_rise",
|
|
4928
|
+
description: "Glowing embers drifting up from the ground and winking out: fire, heat, burning.",
|
|
4929
|
+
loops: true,
|
|
4930
|
+
tags: ["embers", "fire", "sparks", "rising", "heat", "ambient"]
|
|
4931
|
+
},
|
|
4932
|
+
{
|
|
4933
|
+
name: "fire_blast",
|
|
4934
|
+
description: "A drawn explosion: a flash, round fire billows burning out into smoke puffs, a pressure ring. Noise version: fireball.",
|
|
4935
|
+
loops: false,
|
|
4936
|
+
tags: ["explosion", "fire", "blast", "boom", "smoke"]
|
|
4937
|
+
},
|
|
4938
|
+
{
|
|
4939
|
+
name: "fire_ring",
|
|
4940
|
+
description: "A ring of flickering flames standing on the ground around the anchor, embers rising: trapped in fire, burning ground, fire wall.",
|
|
4941
|
+
loops: true,
|
|
4942
|
+
tags: ["fire", "ring", "ground", "flames", "trap", "area"]
|
|
4943
|
+
},
|
|
4944
|
+
{
|
|
4945
|
+
name: "fire_wall",
|
|
4946
|
+
description: "A wide wall of drawn flame: seven tongues rising and flickering from one burning line. Fire walls, burning ground.",
|
|
4947
|
+
loops: true,
|
|
4948
|
+
tags: ["fire", "wall", "barrier", "burning", "loop"]
|
|
4949
|
+
},
|
|
4950
|
+
{
|
|
4951
|
+
name: "fireball",
|
|
4952
|
+
description: "An explosion's fire mass: a flash, billowing fire that burns out into smoke, a pressure ring.",
|
|
4953
|
+
loops: false,
|
|
4954
|
+
tags: ["explosion", "fire", "blast", "boom", "smoke"]
|
|
4955
|
+
},
|
|
4956
|
+
{
|
|
4957
|
+
name: "fireflies",
|
|
4958
|
+
description: "Glowing fireflies drifting slowly and blinking on and off around the anchor: night, forests, swamps, calm magic.",
|
|
4959
|
+
loops: true,
|
|
4960
|
+
tags: ["fireflies", "night", "nature", "ambient", "glow", "forest"]
|
|
4961
|
+
},
|
|
4962
|
+
{
|
|
4963
|
+
name: "fireworks",
|
|
4964
|
+
description: "A rocket streaking up and bursting into a falling shower of sparkles. Celebrations, victories, level-ups.",
|
|
4965
|
+
loops: false,
|
|
4966
|
+
tags: ["fireworks", "celebrate", "victory", "sparkle", "burst"]
|
|
4967
|
+
},
|
|
4968
|
+
{
|
|
4969
|
+
name: "flame_aura",
|
|
4970
|
+
description: "Drawn tongues of power rising behind a standing character, a ring at the feet, sparks. Noise version: aura_flames.",
|
|
4971
|
+
loops: true,
|
|
4972
|
+
tags: ["aura", "power", "buff", "flames", "charge", "rage"]
|
|
4973
|
+
},
|
|
4974
|
+
{
|
|
4975
|
+
name: "flame_jet",
|
|
4976
|
+
description: "A roaring jet of fire blasting sideways (to the right) from the anchor, widening into billows, sparks flying: flamethrower, fire breath.",
|
|
4977
|
+
loops: true,
|
|
4978
|
+
tags: ["fire", "jet", "breath", "flamethrower", "stream", "attack"]
|
|
4979
|
+
},
|
|
4980
|
+
{
|
|
4981
|
+
name: "flame_ring",
|
|
4982
|
+
description: "A ring of drawn flame tongues on the ground around the anchor, embers rising: trapped in fire. Noise version: fire_ring.",
|
|
4983
|
+
loops: true,
|
|
4984
|
+
tags: ["fire", "ring", "ground", "flames", "trap", "area"]
|
|
4985
|
+
},
|
|
4986
|
+
{
|
|
4987
|
+
name: "flame_tongue",
|
|
4988
|
+
description: "One big drawn cartoon flame, wide at the root, its tip whipping and curling: fire elementals, a burning spot, a cartoon blaze.",
|
|
4989
|
+
loops: true,
|
|
4990
|
+
tags: ["fire", "cartoon", "flame", "elemental", "loop"]
|
|
4991
|
+
},
|
|
4992
|
+
{
|
|
4993
|
+
name: "flamethrower",
|
|
4994
|
+
description: "A drawn jet of fire blasting right from the anchor, sparks flying: flamethrower, fire breath. Noise version: flame_jet.",
|
|
4995
|
+
loops: true,
|
|
4996
|
+
tags: ["fire", "jet", "breath", "flamethrower", "stream", "attack"]
|
|
4997
|
+
},
|
|
4998
|
+
{
|
|
4999
|
+
name: "flash_burst",
|
|
5000
|
+
description: "A hit flash: a white-hot core, rays and a ring punching outward. The heart of a hit spark.",
|
|
5001
|
+
loops: false,
|
|
5002
|
+
tags: ["hit", "impact", "flash", "spark", "punch", "rays"]
|
|
5003
|
+
},
|
|
5004
|
+
{
|
|
5005
|
+
name: "freeze_status",
|
|
5006
|
+
description: "Icy crust and cold tint on the sprite, ice crystals around the feet and glinting frost specks: frozen, chilled, slowed.",
|
|
5007
|
+
loops: true,
|
|
5008
|
+
tags: ["freeze", "ice", "status", "frost", "cold"]
|
|
5009
|
+
},
|
|
5010
|
+
{
|
|
5011
|
+
name: "frost_mist",
|
|
5012
|
+
description: "Low cold mist drifting sideways in dithered bands around the feet, a few frost glints: winter, swamps, graveyards, spooky.",
|
|
5013
|
+
loops: true,
|
|
5014
|
+
tags: ["mist", "fog", "frost", "cold", "ground", "ambient"]
|
|
5015
|
+
},
|
|
5016
|
+
{
|
|
5017
|
+
name: "grass_cut",
|
|
5018
|
+
description: "Grass clippings bursting up from a cut tuft and falling back around it. Cutting bushes and grass, trampling, foliage hits.",
|
|
5019
|
+
loops: false,
|
|
5020
|
+
tags: ["grass", "leaves", "cut", "bush", "environment", "nature"]
|
|
5021
|
+
},
|
|
5022
|
+
{
|
|
5023
|
+
name: "ground_cracks",
|
|
5024
|
+
description: "Glowing cracks race out along the ground from the impact point, cool down and fade. Ground slams, earth magic, lava.",
|
|
5025
|
+
loops: false,
|
|
5026
|
+
tags: ["cracks", "ground", "slam", "impact", "earth", "lava"]
|
|
5027
|
+
},
|
|
5028
|
+
{
|
|
5029
|
+
name: "heal_column",
|
|
5030
|
+
description: "A soft column of light standing on the ground, a ring at its base and sparkles rising.",
|
|
5031
|
+
loops: true,
|
|
5032
|
+
tags: ["heal", "holy", "buff", "light", "pillar", "column", "restore"]
|
|
5033
|
+
},
|
|
5034
|
+
{
|
|
5035
|
+
name: "heal_plus",
|
|
5036
|
+
description: "Green plus signs and motes float up off a body that flashes a glowing outline: healing received, regen ticks, potions.",
|
|
5037
|
+
loops: false,
|
|
5038
|
+
tags: ["heal", "plus", "regen", "potion", "restore", "ui"]
|
|
5039
|
+
},
|
|
5040
|
+
{
|
|
5041
|
+
name: "hit_star",
|
|
5042
|
+
description: "A sharp star flashing on the hit point with specks flying off. The classic hit spark for punches and blows.",
|
|
5043
|
+
loops: false,
|
|
5044
|
+
tags: ["hit", "impact", "spark", "star", "punch", "flash"]
|
|
5045
|
+
},
|
|
5046
|
+
{
|
|
5047
|
+
name: "holy_aura",
|
|
5048
|
+
description: "A golden radiance with light spikes behind a character, a glowing rim and streaks of light rising: blessed, divine, holy buff.",
|
|
5049
|
+
loops: true,
|
|
5050
|
+
tags: ["holy", "aura", "light", "buff", "divine", "blessing"]
|
|
5051
|
+
},
|
|
5052
|
+
{
|
|
5053
|
+
name: "hurt_flash",
|
|
5054
|
+
description: "The sprite blinks white twice, its outline lit hot: the classic took-damage flash. Recolour red for damage, gold for buffs.",
|
|
5055
|
+
loops: false,
|
|
5056
|
+
tags: ["hit", "hurt", "damage", "flash", "blink", "sprite"]
|
|
5057
|
+
},
|
|
5058
|
+
{
|
|
5059
|
+
name: "ice_shatter",
|
|
5060
|
+
description: "A flash and a ring of cold, then ice shards bursting out and tumbling down. Breaking a freeze, an ice spell's hit.",
|
|
5061
|
+
loops: false,
|
|
5062
|
+
tags: ["ice", "shatter", "frost", "break", "hit"]
|
|
5063
|
+
},
|
|
5064
|
+
{
|
|
5065
|
+
name: "ice_spikes",
|
|
5066
|
+
description: "A cluster of faceted ice spikes erupting from the ground under the anchor, holding, then sinking back: frost attacks, traps.",
|
|
5067
|
+
loops: false,
|
|
5068
|
+
tags: ["ice", "frost", "spikes", "ground", "attack", "freeze"]
|
|
5069
|
+
},
|
|
5070
|
+
{
|
|
5071
|
+
name: "item_glint",
|
|
5072
|
+
description: "A sharp four-point glint flashes now and then on an item's upper right, a smaller one lower left: shiny pickups, gems, loot.",
|
|
5073
|
+
loops: true,
|
|
5074
|
+
tags: ["glint", "shine", "pickup", "gem", "loot", "sparkle"]
|
|
5075
|
+
},
|
|
5076
|
+
{
|
|
5077
|
+
name: "landing_dust",
|
|
5078
|
+
description: "Drawn dust clouds rolling out flat to both sides of a landing and thinning away. Heavy landings, stomps, slides.",
|
|
5079
|
+
loops: false,
|
|
5080
|
+
tags: ["dust", "landing", "ground", "stomp", "cartoon"]
|
|
5081
|
+
},
|
|
5082
|
+
{
|
|
5083
|
+
name: "lava_pool",
|
|
5084
|
+
description: "A slowly churning pool of glowing lava on the ground with bubbles popping and embers: lava, molten ground, fire traps, hell.",
|
|
5085
|
+
loops: true,
|
|
5086
|
+
tags: ["lava", "fire", "pool", "ground", "molten", "hazard"]
|
|
5087
|
+
},
|
|
5088
|
+
{
|
|
5089
|
+
name: "leaf_fall",
|
|
5090
|
+
description: "Autumn leaves drifting down and swaying around the anchor: forests, autumn, wind, nature magic, a shaken tree.",
|
|
5091
|
+
loops: true,
|
|
5092
|
+
tags: ["leaves", "nature", "autumn", "weather", "ambient", "falling"]
|
|
5093
|
+
},
|
|
5094
|
+
{
|
|
5095
|
+
name: "level_up",
|
|
5096
|
+
description: "A pillar of light bursts up from the feet, halos rise up the body, up-arrows and sparkles float away: level up, rank up, power gain.",
|
|
5097
|
+
loops: false,
|
|
5098
|
+
tags: ["levelup", "pillar", "buff", "reward", "holy", "arrows"]
|
|
5099
|
+
},
|
|
5100
|
+
{
|
|
5101
|
+
name: "lightning_arcs",
|
|
5102
|
+
description: "Small jagged arcs of electricity crackling on and off around a body, with spark glints: shocked, charged, electrified.",
|
|
5103
|
+
loops: true,
|
|
5104
|
+
tags: ["lightning", "electric", "shock", "status", "crackle", "charge"]
|
|
5105
|
+
},
|
|
5106
|
+
{
|
|
5107
|
+
name: "magic_orb",
|
|
5108
|
+
description: "A glowing orb on the anchor with a tapered tail and motes streaming left: a magic missile flying right (+x).",
|
|
5109
|
+
loops: true,
|
|
5110
|
+
tags: ["projectile", "orb", "magic", "missile", "spell", "trail"]
|
|
5111
|
+
},
|
|
5112
|
+
{
|
|
5113
|
+
name: "muzzle_flash",
|
|
5114
|
+
description: "A bright three-pronged flash bursting right (+x) from the anchor, then sparks and a smoke wisp: gunshots, cannons, wands.",
|
|
5115
|
+
loops: false,
|
|
5116
|
+
tags: ["muzzle", "flash", "gun", "shot", "fire", "projectile"]
|
|
5117
|
+
},
|
|
5118
|
+
{
|
|
5119
|
+
name: "on_fire",
|
|
5120
|
+
description: "Small drawn flames licking up around a character, embers, a hot rim: on fire, burn damage. Noise version: burn_status.",
|
|
5121
|
+
loops: true,
|
|
5122
|
+
tags: ["burn", "fire", "status", "flames", "dot"]
|
|
5123
|
+
},
|
|
5124
|
+
{
|
|
5125
|
+
name: "orbit_motes",
|
|
5126
|
+
description: "Glowing motes and glints circling a character, passing in front and behind: magic charge, enchantment, wisps, a buff.",
|
|
5127
|
+
loops: true,
|
|
5128
|
+
tags: ["orbit", "motes", "magic", "buff", "arcane", "aura"]
|
|
5129
|
+
},
|
|
5130
|
+
{
|
|
5131
|
+
name: "poison_bubbles",
|
|
5132
|
+
description: "Green bubbles and specks rising off the body and popping, with a sickly pulsing rim on the sprite: poisoned, toxic, sick.",
|
|
5133
|
+
loops: true,
|
|
5134
|
+
tags: ["poison", "status", "bubbles", "toxic", "debuff"]
|
|
5135
|
+
},
|
|
5136
|
+
{
|
|
5137
|
+
name: "portal_swirl",
|
|
5138
|
+
description: "An upright swirling portal: churning core, glowing rim, orbiting motes.",
|
|
5139
|
+
loops: true,
|
|
5140
|
+
tags: ["portal", "void", "gate", "teleport", "magic", "arcane"]
|
|
5141
|
+
},
|
|
5142
|
+
{
|
|
5143
|
+
name: "rain_streaks",
|
|
5144
|
+
description: "Rain falling straight down as thin streaks, near and far, with little splashes on the ground: wet weather, storms, gloom.",
|
|
5145
|
+
loops: true,
|
|
5146
|
+
tags: ["rain", "weather", "water", "storm", "ambient"]
|
|
5147
|
+
},
|
|
5148
|
+
{
|
|
5149
|
+
name: "rocket_exhaust",
|
|
5150
|
+
description: "Round smoke puffs streaming left from an exhaust flame, flying right (+x): rockets, fire trails. Noise version: smoke_trail.",
|
|
5151
|
+
loops: true,
|
|
5152
|
+
tags: ["trail", "smoke", "rocket", "exhaust", "projectile", "missile"]
|
|
5153
|
+
},
|
|
5154
|
+
{
|
|
5155
|
+
name: "rune_circle",
|
|
5156
|
+
description: "A magic circle on the ground: rings, a hexagram and a rune band turning slowly, twinkling motes.",
|
|
5157
|
+
loops: true,
|
|
5158
|
+
tags: ["magic", "circle", "sigil", "summon", "ground", "arcane"]
|
|
5159
|
+
},
|
|
5160
|
+
{
|
|
5161
|
+
name: "rune_orbit",
|
|
5162
|
+
description: "Four glowing rune glyphs evenly circling a character's waist on a faint ring, in front and behind: spellcasting, enchant, arcane buff.",
|
|
5163
|
+
loops: true,
|
|
5164
|
+
tags: ["runes", "orbit", "arcane", "magic", "buff", "enchant"]
|
|
5165
|
+
},
|
|
5166
|
+
{
|
|
5167
|
+
name: "scorch_mark",
|
|
5168
|
+
description: "A charred patch on the ground with embers smouldering and flickering in it. Loop: after explosions, fire spells, burning.",
|
|
5169
|
+
loops: true,
|
|
5170
|
+
tags: ["scorch", "burn", "ground", "fire", "embers", "aftermath"]
|
|
5171
|
+
},
|
|
5172
|
+
{
|
|
5173
|
+
name: "shadow_aura",
|
|
5174
|
+
description: "Dark smoke wisps billowing up behind a character from a shadow pool, pale motes rising: dark power, curse, corruption.",
|
|
5175
|
+
loops: true,
|
|
5176
|
+
tags: ["shadow", "aura", "dark", "curse", "smoke", "debuff"]
|
|
5177
|
+
},
|
|
5178
|
+
{
|
|
5179
|
+
name: "shield_break",
|
|
5180
|
+
description: "A bubble shield flickering, then bursting in a flash into shards that fly out and fall. A broken guard or barrier.",
|
|
5181
|
+
loops: false,
|
|
5182
|
+
tags: ["shield", "break", "barrier", "bubble", "shatter"]
|
|
5183
|
+
},
|
|
5184
|
+
{
|
|
5185
|
+
name: "shockwave_ring",
|
|
5186
|
+
description: "A ring of force racing out along the ground with dust kicked up. A stomp, a landing, an impact.",
|
|
5187
|
+
loops: false,
|
|
5188
|
+
tags: ["impact", "stomp", "landing", "ground", "ring", "dust"]
|
|
5189
|
+
},
|
|
5190
|
+
{
|
|
5191
|
+
name: "sky_beam",
|
|
5192
|
+
description: "A pillar of light slams down onto the anchor, flares wide, rings out on the ground and thins away: smite, blessing, summon, revive.",
|
|
5193
|
+
loops: false,
|
|
5194
|
+
tags: ["beam", "holy", "light", "smite", "summon", "revive"]
|
|
5195
|
+
},
|
|
5196
|
+
{
|
|
5197
|
+
name: "slam_dust",
|
|
5198
|
+
description: "Round dust clouds billowing out and up from a ground impact: landings, slams, boulders. Noise version: crater_dust.",
|
|
5199
|
+
loops: false,
|
|
5200
|
+
tags: ["dust", "impact", "ground", "slam", "landing", "cloud"]
|
|
5201
|
+
},
|
|
5202
|
+
{
|
|
5203
|
+
name: "slash_trail",
|
|
5204
|
+
description: "A weapon swing: a bright crescent sweeping past the sprite, then dithering away. Sword, axe and claw swings.",
|
|
5205
|
+
loops: false,
|
|
5206
|
+
tags: ["slash", "swing", "sword", "melee", "hit", "arc"]
|
|
5207
|
+
},
|
|
5208
|
+
{
|
|
5209
|
+
name: "sleep_zzz",
|
|
5210
|
+
description: "Z letters drifting up and to the right off the head, growing as they rise and fading: asleep, resting, sleep status.",
|
|
5211
|
+
loops: true,
|
|
5212
|
+
tags: ["sleep", "zzz", "status", "rest", "idle"]
|
|
5213
|
+
},
|
|
5214
|
+
{
|
|
5215
|
+
name: "smoke_column",
|
|
5216
|
+
description: "A looping column of drawn smoke puffs rising, swaying, growing and fading. Chimneys, campfires, burning wrecks.",
|
|
5217
|
+
loops: true,
|
|
5218
|
+
tags: ["smoke", "column", "chimney", "fire", "loop"]
|
|
5219
|
+
},
|
|
5220
|
+
{
|
|
5221
|
+
name: "smoke_poof",
|
|
5222
|
+
description: "A drawn cartoon poof: round smoke puffs bursting out all round, rising and burning away. Vanish, teleport (z front hides the sprite).",
|
|
5223
|
+
loops: false,
|
|
5224
|
+
tags: ["smoke", "poof", "cartoon", "vanish", "teleport"]
|
|
5225
|
+
},
|
|
5226
|
+
{
|
|
5227
|
+
name: "smoke_puff",
|
|
5228
|
+
description: "A puff of smoke that billows up and thins away: dust clouds, poofs, after an explosion.",
|
|
5229
|
+
loops: false,
|
|
5230
|
+
tags: ["smoke", "puff", "poof", "dust", "cloud"]
|
|
5231
|
+
},
|
|
5232
|
+
{
|
|
5233
|
+
name: "smoke_trail",
|
|
5234
|
+
description: "A churning smoke plume streaming left from an exhaust flame on the anchor, flying right (+x): rockets; a fire trail in fire colour.",
|
|
5235
|
+
loops: true,
|
|
5236
|
+
tags: ["trail", "smoke", "rocket", "exhaust", "projectile", "missile"]
|
|
5237
|
+
},
|
|
5238
|
+
{
|
|
5239
|
+
name: "snowfall",
|
|
5240
|
+
description: "Snowflakes drifting down around the anchor, near ones as little crystals, far ones as dots.",
|
|
5241
|
+
loops: true,
|
|
5242
|
+
tags: ["snow", "weather", "winter", "cold", "ambient", "ice"]
|
|
5243
|
+
},
|
|
5244
|
+
{
|
|
5245
|
+
name: "soft_glow",
|
|
5246
|
+
description: "A soft pool of light on the ground, gently breathing: under a character, a pickup, a lamp.",
|
|
5247
|
+
loops: true,
|
|
5248
|
+
tags: ["glow", "light", "ground", "pool", "ambient", "aura"]
|
|
5249
|
+
},
|
|
5250
|
+
{
|
|
5251
|
+
name: "spark_burst",
|
|
5252
|
+
description: "Sparks flying out of a point and fading: hits, clashes, sword strikes, electricity.",
|
|
5253
|
+
loops: false,
|
|
5254
|
+
tags: ["sparks", "hit", "clash", "impact", "electric"]
|
|
5255
|
+
},
|
|
5256
|
+
{
|
|
5257
|
+
name: "sparks_shower",
|
|
5258
|
+
description: "Hot sparks spraying out of a point in a cone and arcing down: metal on metal, sword clashes, grinding, welding.",
|
|
5259
|
+
loops: false,
|
|
5260
|
+
tags: ["sparks", "metal", "clash", "hit", "shower", "impact"]
|
|
5261
|
+
},
|
|
5262
|
+
{
|
|
5263
|
+
name: "speed_lines",
|
|
5264
|
+
description: "Pale wind streaks rushing left past the anchor, behind and over a sprite moving right (+x): dashes, sprints, charges.",
|
|
5265
|
+
loops: true,
|
|
5266
|
+
tags: ["speed", "dash", "motion", "wind", "lines", "movement"]
|
|
5267
|
+
},
|
|
5268
|
+
{
|
|
5269
|
+
name: "sprite_dust",
|
|
5270
|
+
description: "The sprite's own pixels lifting off as dust and drifting away: disintegrate, fade out, teleport out (pair with the sprite's dissolve).",
|
|
5271
|
+
loops: false,
|
|
5272
|
+
tags: ["disintegrate", "dust", "teleport", "vanish", "sprite"]
|
|
5273
|
+
},
|
|
5274
|
+
{
|
|
5275
|
+
name: "square_sigil",
|
|
5276
|
+
description: "A ground seal of two counter-turning squares inside two rings, a glowing heart and motes rising: casting, warding, a trap glyph.",
|
|
5277
|
+
loops: true,
|
|
5278
|
+
tags: ["sigil", "magic", "circle", "ground", "ward", "arcane"]
|
|
5279
|
+
},
|
|
5280
|
+
{
|
|
5281
|
+
name: "star_burst",
|
|
5282
|
+
description: "Chunky cartoon stars pop out of the anchor in a ring and hang before blinking away: bonks, KOs, rewards, pickups.",
|
|
5283
|
+
loops: false,
|
|
5284
|
+
tags: ["stars", "cartoon", "burst", "hit", "reward", "pickup"]
|
|
5285
|
+
},
|
|
5286
|
+
{
|
|
5287
|
+
name: "steam_puffs",
|
|
5288
|
+
description: "A steam jet from the ground, round puffs that billow up and dissolve: vents, geysers, kettles. Noise version: steam_vent.",
|
|
5289
|
+
loops: true,
|
|
5290
|
+
tags: ["steam", "smoke", "vent", "geyser", "rising", "ambient"]
|
|
5291
|
+
},
|
|
5292
|
+
{
|
|
5293
|
+
name: "steam_vent",
|
|
5294
|
+
description: "A hissing jet of steam from a point on the ground, puffs that billow up, widen and dissolve: vents, geysers, kettles, hot springs.",
|
|
5295
|
+
loops: true,
|
|
5296
|
+
tags: ["steam", "smoke", "vent", "geyser", "rising", "ambient"]
|
|
5297
|
+
},
|
|
5298
|
+
{
|
|
5299
|
+
name: "stun_stars",
|
|
5300
|
+
description: "Three little stars circling evenly just above the head on a faint ring, passing in front and behind: stunned, dazed, dizzy.",
|
|
5301
|
+
loops: true,
|
|
5302
|
+
tags: ["stun", "dizzy", "stars", "status", "daze"]
|
|
5303
|
+
},
|
|
5304
|
+
{
|
|
5305
|
+
name: "swing_slash",
|
|
5306
|
+
description: "A drawn weapon swing that whips: the edge races round, then is reeled in from behind and crumbles. Swords, axes.",
|
|
5307
|
+
loops: false,
|
|
5308
|
+
tags: ["slash", "sword", "swing", "melee", "hit"]
|
|
5309
|
+
},
|
|
5310
|
+
{
|
|
5311
|
+
name: "teleport_in",
|
|
5312
|
+
description: "Motes swirling in and a column of light narrowing to a flash where the sprite appears. Arrivals, summons, respawns.",
|
|
5313
|
+
loops: false,
|
|
5314
|
+
tags: ["teleport", "arrive", "summon", "beam", "magic"]
|
|
5315
|
+
},
|
|
5316
|
+
{
|
|
5317
|
+
name: "thrust_streak",
|
|
5318
|
+
description: "A straight lance of light stabbing out from the sprite and fading forward, with speed lines. Spear, rapier, dash attacks.",
|
|
5319
|
+
loops: false,
|
|
5320
|
+
tags: ["thrust", "stab", "spear", "melee", "dash", "hit"]
|
|
5321
|
+
},
|
|
5322
|
+
{
|
|
5323
|
+
name: "torch_fire",
|
|
5324
|
+
description: "A drawn torch flame: three teardrop tongues whipping at the tips, a spark or two, lighting the sprite. Torches, braziers.",
|
|
5325
|
+
loops: true,
|
|
5326
|
+
tags: ["fire", "torch", "flame", "brazier", "loop"]
|
|
5327
|
+
},
|
|
5328
|
+
{
|
|
5329
|
+
name: "torch_flame",
|
|
5330
|
+
description: "A small flickering teardrop flame with a licking tongue and a spark or two: torches, candles, braziers, a burning spot.",
|
|
5331
|
+
loops: true,
|
|
5332
|
+
tags: ["fire", "flame", "torch", "light", "ambient"]
|
|
5333
|
+
},
|
|
5334
|
+
{
|
|
5335
|
+
name: "twinkles",
|
|
5336
|
+
description: "Little stars twinkling in and out around the anchor: magic, shine, enchantment, treasure.",
|
|
5337
|
+
loops: true,
|
|
5338
|
+
tags: ["sparkles", "twinkle", "magic", "shine", "stars", "ambient"]
|
|
5339
|
+
},
|
|
5340
|
+
{
|
|
5341
|
+
name: "vine_growth",
|
|
5342
|
+
description: "Twisting green vines sprouting from the ground and curling up around the anchor, leaves popping, then withering: entangle, roots, nature.",
|
|
5343
|
+
loops: false,
|
|
5344
|
+
tags: ["nature", "vines", "roots", "entangle", "growth", "ground"]
|
|
5345
|
+
},
|
|
5346
|
+
{
|
|
5347
|
+
name: "water_drips",
|
|
5348
|
+
description: "Water drops forming on a body and dripping off its lower half, wet glints: soaked, wet status, just out of water, melting.",
|
|
5349
|
+
loops: true,
|
|
5350
|
+
tags: ["water", "drips", "wet", "status", "soaked"]
|
|
5351
|
+
},
|
|
5352
|
+
{
|
|
5353
|
+
name: "water_ripple",
|
|
5354
|
+
description: "Thin rings rippling out on a water surface around the feet, with glints. Loop for wading, standing in water, puddles.",
|
|
5355
|
+
loops: true,
|
|
5356
|
+
tags: ["water", "ripple", "wading", "environment", "ambient", "puddle"]
|
|
5357
|
+
},
|
|
5358
|
+
{
|
|
5359
|
+
name: "water_splash",
|
|
5360
|
+
description: "A crown of droplets thrown up out of water and falling back, with ripples spreading on the surface. Landings, dives, stones.",
|
|
5361
|
+
loops: false,
|
|
5362
|
+
tags: ["water", "splash", "droplets", "ripple", "landing", "environment"]
|
|
5363
|
+
},
|
|
5364
|
+
{
|
|
5365
|
+
name: "wind_gusts",
|
|
5366
|
+
description: "Light streaks of wind sweeping left to right across the anchor with flecks of debris: wind, gales, speed, haste.",
|
|
5367
|
+
loops: true,
|
|
5368
|
+
tags: ["wind", "air", "gust", "weather", "speed", "ambient"]
|
|
5369
|
+
},
|
|
5370
|
+
{
|
|
5371
|
+
name: "zigzag_slash",
|
|
5372
|
+
description: "A slash along a path, not a circle: a zigzag (sharp corners, frantic cuts) or an S (smooth). Reshape it by patching its points.",
|
|
5373
|
+
loops: false,
|
|
5374
|
+
tags: ["slash", "zigzag", "sword", "axe", "melee", "hit", "combo", "path"]
|
|
5375
|
+
}
|
|
5376
|
+
];
|
|
5377
|
+
const PRESET_NAMES = new Set(VFX_PRESETS.map((preset) => preset.name));
|
|
5378
|
+
const PART_NAMES = new Map(VFX_PARTS.map((part) => [part.name, part]));
|
|
5379
|
+
const HEX = /^#[0-9a-f]{6}$/i;
|
|
5380
|
+
const SLIDERS = ["size", "amount", "speed", "start", "end"];
|
|
5381
|
+
function colourProblem(colour) {
|
|
5382
|
+
if (typeof colour === "string") {
|
|
5383
|
+
return VFX_RAMPS.includes(colour) ? null : `"${colour}" is not a colour ramp`;
|
|
5384
|
+
}
|
|
5385
|
+
if (!Array.isArray(colour) || colour.length < VFX_COLOURS_RANGE.min || colour.length > VFX_COLOURS_RANGE.max || !colour.every((one) => typeof one === "string" && HEX.test(one))) {
|
|
5386
|
+
return `a colour is a ramp's name or ${VFX_COLOURS_RANGE.min}–${VFX_COLOURS_RANGE.max} #rrggbb colours`;
|
|
5387
|
+
}
|
|
5388
|
+
return null;
|
|
5389
|
+
}
|
|
5390
|
+
function partProblem(part, at) {
|
|
5391
|
+
if (!PART_NAMES.has(part.part)) return `part ${at}: "${part.part}" is not a part`;
|
|
5392
|
+
if (part.colour !== void 0) {
|
|
5393
|
+
const problem = colourProblem(part.colour);
|
|
5394
|
+
if (problem) return `part ${at}: ${problem}`;
|
|
5395
|
+
}
|
|
5396
|
+
for (const slider of SLIDERS) {
|
|
5397
|
+
const value = part[slider];
|
|
5398
|
+
if (value === void 0) continue;
|
|
5399
|
+
const { min, max } = VFX_SLIDERS[slider];
|
|
5400
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < min || value > max) {
|
|
5401
|
+
return `part ${at}: ${slider} is between ${min} and ${max}`;
|
|
5402
|
+
}
|
|
5403
|
+
}
|
|
5404
|
+
if ((part.start ?? 0) >= (part.end ?? 1)) return `part ${at}: start comes before end`;
|
|
5405
|
+
return null;
|
|
5406
|
+
}
|
|
5407
|
+
function vfxProblem(ask) {
|
|
5408
|
+
const hasPreset = ask.preset !== void 0;
|
|
5409
|
+
const hasParts = ask.parts !== void 0;
|
|
5410
|
+
if (hasPreset === hasParts) return "an effect is a preset or parts, one of the two";
|
|
5411
|
+
if (hasPreset) return PRESET_NAMES.has(ask.preset) ? null : `"${ask.preset}" is not a preset`;
|
|
5412
|
+
const parts = ask.parts;
|
|
5413
|
+
if (parts.length < VFX_PARTS_RANGE.min || parts.length > VFX_PARTS_RANGE.max) {
|
|
5414
|
+
return `an effect has ${VFX_PARTS_RANGE.min} to ${VFX_PARTS_RANGE.max} parts`;
|
|
5415
|
+
}
|
|
5416
|
+
for (const [index, part] of parts.entries()) {
|
|
5417
|
+
const problem = partProblem(part, index + 1);
|
|
5418
|
+
if (problem) return problem;
|
|
5419
|
+
}
|
|
5420
|
+
return null;
|
|
5421
|
+
}
|
|
4680
5422
|
const MORE_KINDS = {
|
|
4681
5423
|
variant: "a variant",
|
|
4682
5424
|
edit: "an edit",
|
|
@@ -4688,7 +5430,8 @@ const MORE_KINDS = {
|
|
|
4688
5430
|
"terrain-animation": "an animated terrain set",
|
|
4689
5431
|
sfx: "a sound effect",
|
|
4690
5432
|
speech: "speech",
|
|
4691
|
-
music: "music"
|
|
5433
|
+
music: "music",
|
|
5434
|
+
vfx: "a visual effect"
|
|
4692
5435
|
};
|
|
4693
5436
|
const MORE_NAMES = { state: "creature-state", "animated-terrain": "terrain-animation" };
|
|
4694
5437
|
const UUID$4 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
@@ -4725,7 +5468,10 @@ const OWN_OPTIONS = {
|
|
|
4725
5468
|
voice: ["speech"],
|
|
4726
5469
|
seconds: ["sfx"],
|
|
4727
5470
|
loop: ["sfx"],
|
|
4728
|
-
out: ["sfx", "speech", "music"]
|
|
5471
|
+
out: ["sfx", "speech", "music", "vfx"],
|
|
5472
|
+
preset: ["vfx"],
|
|
5473
|
+
part: ["vfx"],
|
|
5474
|
+
subject: ["vfx"]
|
|
4729
5475
|
};
|
|
4730
5476
|
const MORE_OPTIONS = {
|
|
4731
5477
|
source: { type: "string", value: "<image id>", description: "a change's picture: an image of the account's, such as a generation's or a sprite's" },
|
|
@@ -4764,7 +5510,23 @@ const MORE_OPTIONS = {
|
|
|
4764
5510
|
voice: { type: "string", value: "<voice>", description: `the voice speech is said in: ${VOICES.join(", ")}` },
|
|
4765
5511
|
seconds: { type: "string", value: "<seconds>", description: `a sound effect's length, ${SFX_SECONDS.min} to ${SFX_SECONDS.max}` },
|
|
4766
5512
|
loop: { type: "boolean", description: "a sound effect that loops seamlessly" },
|
|
4767
|
-
out: {
|
|
5513
|
+
out: {
|
|
5514
|
+
type: "string",
|
|
5515
|
+
value: "<path>",
|
|
5516
|
+
description: "where a sound is written, pixelvibing/sounds/ unless given; the folder an effect's frames are written in, pixelvibing/effects/ unless given"
|
|
5517
|
+
},
|
|
5518
|
+
preset: { type: "string", value: "<preset>", description: `a ready visual effect: ${VFX_PRESETS.map((preset) => preset.name).join(", ")}` },
|
|
5519
|
+
part: {
|
|
5520
|
+
type: "string",
|
|
5521
|
+
multiple: true,
|
|
5522
|
+
value: "<part>[,colour=<ramp|#rrggbb/#rrggbb…>][,size=<n>][,amount=<n>][,speed=<n>][,start=<0-1>][,end=<0-1>]",
|
|
5523
|
+
description: `a part of a visual effect, given once for each, up to six: ${VFX_PARTS.map((part) => part.name).join(", ")}; colour is a ramp (${VFX_RAMPS.join(", ")}) or colours dark to light`
|
|
5524
|
+
},
|
|
5525
|
+
subject: {
|
|
5526
|
+
type: "string",
|
|
5527
|
+
value: "<image id>",
|
|
5528
|
+
description: "the image a visual effect is drawn around, an image of the account's of at most 256 px a side"
|
|
5529
|
+
}
|
|
4768
5530
|
};
|
|
4769
5531
|
function wholeOf(args, name, least, most) {
|
|
4770
5532
|
const given2 = stringOf(args, name);
|
|
@@ -4780,6 +5542,21 @@ function fractionOf(args, name, least, most) {
|
|
|
4780
5542
|
if (!Number.isFinite(value) || value < least || value > most) throw new CliError(`--${name} is a number from ${least} to ${most}`);
|
|
4781
5543
|
return value;
|
|
4782
5544
|
}
|
|
5545
|
+
function partOf(given2) {
|
|
5546
|
+
const [name, ...settings] = given2.split(",").map((each) => each.trim());
|
|
5547
|
+
const part = { part: name ?? "" };
|
|
5548
|
+
for (const setting of settings) {
|
|
5549
|
+
const [key, value] = setting.split("=").map((each) => each.trim());
|
|
5550
|
+
if (value === void 0 || value === "") throw new CliError(`--part's ${key} is given as ${key}=<value>`);
|
|
5551
|
+
if (key === "colour" || key === "color") part.colour = value.includes("/") || value.startsWith("#") ? value.split("/") : value;
|
|
5552
|
+
else if (key === "size" || key === "amount" || key === "speed" || key === "start" || key === "end") {
|
|
5553
|
+
const number2 = Number(value);
|
|
5554
|
+
if (!Number.isFinite(number2)) throw new CliError(`--part's ${key} is a number`);
|
|
5555
|
+
part[key] = number2;
|
|
5556
|
+
} else throw new CliError(`--part takes colour, size, amount, speed, start and end, not ${key}`);
|
|
5557
|
+
}
|
|
5558
|
+
return part;
|
|
5559
|
+
}
|
|
4783
5560
|
const given = (args, name) => args.values[name] !== void 0;
|
|
4784
5561
|
function ownOnly(args, kind) {
|
|
4785
5562
|
for (const [option, kinds] of Object.entries(OWN_OPTIONS)) {
|
|
@@ -4887,6 +5664,18 @@ async function moreRequest(context, kind, args, instruction, reference) {
|
|
|
4887
5664
|
words: `${words} from ${terrain}${instruction === "" ? "" : `: ${instruction}`}`
|
|
4888
5665
|
};
|
|
4889
5666
|
}
|
|
5667
|
+
if (kind === "vfx") {
|
|
5668
|
+
const preset = stringOf(args, "preset");
|
|
5669
|
+
const given2 = args.values.part;
|
|
5670
|
+
const parts = given2 === void 0 ? void 0 : (Array.isArray(given2) ? given2 : [given2]).map((each) => partOf(String(each)));
|
|
5671
|
+
const ask = { ...preset === void 0 ? {} : { preset }, ...parts === void 0 ? {} : { parts } };
|
|
5672
|
+
const problem = vfxProblem(ask);
|
|
5673
|
+
if (problem !== null) throw new CliError(`${problem}: give --preset, or --part once for each part`);
|
|
5674
|
+
const subject = stringOf(args, "subject");
|
|
5675
|
+
if (subject !== void 0 && !UUID$4.test(subject)) throw new CliError("--subject is an image's id");
|
|
5676
|
+
const what = preset ?? (parts ?? []).map((each) => each.part).join(", ");
|
|
5677
|
+
return { kind, body: { ...ask, ...subject === void 0 ? {} : { subject } }, words: `${words}: ${what.replace(/_/g, " ")}` };
|
|
5678
|
+
}
|
|
4890
5679
|
if (kind === "speech") {
|
|
4891
5680
|
const text2 = stringOf(args, "text")?.trim() ?? "";
|
|
4892
5681
|
const voice = stringOf(args, "voice");
|
|
@@ -4923,7 +5712,7 @@ async function withPatch(platform, project, request) {
|
|
|
4923
5712
|
return { ...request, body: { ...body, upperLabel, lowerLabel }, images: { patch } };
|
|
4924
5713
|
}
|
|
4925
5714
|
function landsInArt(kind, request) {
|
|
4926
|
-
if (SOUNDS.has(kind) || kind === "terrain" || kind === "terrain-animation") return false;
|
|
5715
|
+
if (SOUNDS.has(kind) || kind === "terrain" || kind === "terrain-animation" || kind === "vfx") return false;
|
|
4927
5716
|
return !(KEPT_WITH_A_SPRITE.has(kind) && request.body.into !== void 0);
|
|
4928
5717
|
}
|
|
4929
5718
|
async function finishedMore(context, platform, local, kind, job, args) {
|
|
@@ -4948,6 +5737,33 @@ async function finishedMore(context, platform, local, kind, job, args) {
|
|
|
4948
5737
|
}
|
|
4949
5738
|
return { value: { job: job.id, sounds: written }, words: `Wrote ${written.join(", ")}.` };
|
|
4950
5739
|
}
|
|
5740
|
+
if (kind === "vfx") {
|
|
5741
|
+
const frames = job.result?.images ?? [];
|
|
5742
|
+
if (frames.length === 0) throw new CliError("the job is done, and made no frame");
|
|
5743
|
+
const out = stringOf(args, "out");
|
|
5744
|
+
const folder = out === void 0 ? join(artOf(local), "effects", `vfx-${job.id.slice(0, 8)}`) : resolve(context.io.cwd, out);
|
|
5745
|
+
const data = job.result?.data ?? {};
|
|
5746
|
+
const names = frames.map((_, index) => `frame-${String(index + 1).padStart(2, "0")}.png`);
|
|
5747
|
+
const timings = {
|
|
5748
|
+
frames: names.map((file, index) => ({ file, ms: data.frames?.[index]?.ms ?? null })),
|
|
5749
|
+
width: data.width ?? null,
|
|
5750
|
+
height: data.height ?? null,
|
|
5751
|
+
anchor: data.anchor ?? null,
|
|
5752
|
+
loops: data.loops === true
|
|
5753
|
+
};
|
|
5754
|
+
const files = [];
|
|
5755
|
+
for (const [index, frame] of frames.entries()) files.push([join(folder, names[index]), await platform.web.imageBytes(frame)]);
|
|
5756
|
+
files.push([join(folder, "effect.json"), new TextEncoder().encode(`${JSON.stringify(timings, null, 2)}
|
|
5757
|
+
`)]);
|
|
5758
|
+
for (const [target, bytes] of files) {
|
|
5759
|
+
if (out === void 0) await artBoundary(local).writeFileReplacing(target, bytes);
|
|
5760
|
+
else {
|
|
5761
|
+
await mkdir(dirname(target), { recursive: true });
|
|
5762
|
+
await writeFile(target, bytes);
|
|
5763
|
+
}
|
|
5764
|
+
}
|
|
5765
|
+
return { value: { job: job.id, effect: folder, frames: frames.length }, words: `Wrote ${frames.length} frames and effect.json into ${folder}.` };
|
|
5766
|
+
}
|
|
4951
5767
|
if (kind === "terrain" || kind === "terrain-animation") {
|
|
4952
5768
|
return {
|
|
4953
5769
|
value: { job: job.id },
|
|
@@ -5203,8 +6019,8 @@ async function followed(context, platform, jobId) {
|
|
|
5203
6019
|
}
|
|
5204
6020
|
const generate = {
|
|
5205
6021
|
name: "generate",
|
|
5206
|
-
summary: "Generate an asset, a change of a picture, terrain or a
|
|
5207
|
-
usage: "<object|creature|concept-art|icons|ui|variant|edit|animate|pose|rotate|state|terrain|terrain-animation|sfx|speech|music> [--instruction <text>] [--source <image id>] [--state <state>] [--into <sprite> --name <name>] [--upper <ground> --lower <ground>] [--terrain <asset>] [--text <text> --voice <voice>] [--out <
|
|
6022
|
+
summary: "Generate an asset, a change of a picture, terrain, a sound or a visual effect on the platform, then pull it, keep it or write it",
|
|
6023
|
+
usage: "<object|creature|concept-art|icons|ui|variant|edit|animate|pose|rotate|state|terrain|terrain-animation|sfx|speech|music|vfx> [--instruction <text>] [--source <image id>] [--state <state>] [--into <sprite> --name <name>] [--upper <ground> --lower <ground>] [--terrain <asset>] [--text <text> --voice <voice>] [--preset <preset> | --part <part>…] [--subject <image id>] [--out <path>] [--size <c>x<r>|<w>x<h>|<px>] [--transparent] [--pixel-art] [--tiles <c>x<r>] [--tag <tag>]… [--mask <png>] [--names <list>] [--purpose skill|item] [--sketch <json>] [--reference <png>]… [--no-enrich] [--yes]",
|
|
5208
6024
|
options: {
|
|
5209
6025
|
instruction: {
|
|
5210
6026
|
type: "string",
|
|
@@ -5739,7 +6555,7 @@ const move = {
|
|
|
5739
6555
|
);
|
|
5740
6556
|
}
|
|
5741
6557
|
};
|
|
5742
|
-
const version = "0.
|
|
6558
|
+
const version = "0.54.0";
|
|
5743
6559
|
const manifest = {
|
|
5744
6560
|
version
|
|
5745
6561
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixelvibing/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.0",
|
|
4
4
|
"description": "PixelVibing: pixel art game assets from the command line, and the Skills that teach coding assistants to make them.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://pixelvibing.com",
|
|
@@ -48,6 +48,7 @@ Load the Skill for the kind before you generate it:
|
|
|
48
48
|
| another of a result, a change to it, setting it in motion, a pose, turning it, a creature's state | `pixelvibing-change` |
|
|
49
49
|
| ground that joins everywhere, or ground that moves | `pixelvibing-terrain` |
|
|
50
50
|
| a sound effect, a line of speech, a piece of music | `pixelvibing-sound` |
|
|
51
|
+
| a spell, a hit, an explosion, an aura: an animated visual effect | `pixelvibing-effect` |
|
|
51
52
|
|
|
52
53
|
## What every generation shares
|
|
53
54
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pixelvibing-effect
|
|
3
|
+
description: Generate visual effects for this game on PixelVibing — an animated spell, hit, explosion, aura, shield or portal, from a ready preset or built from parts, around one of the game's sprites or on its own — with pixel-vibing-cli or the PixelVibing MCP server, written as frames with their timings. Use when the game needs an effect.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Visual effect
|
|
7
|
+
|
|
8
|
+
Load the `pixelvibing` Skill first: who is signed in, the limit.
|
|
9
|
+
|
|
10
|
+
An effect is drawn from a ready **preset** or from tuned **parts**, never from words: pick the
|
|
11
|
+
ones that fit what the person describes. `pixel-vibing-cli generate --help` lists every preset
|
|
12
|
+
and part by name; read it rather than guessing one.
|
|
13
|
+
|
|
14
|
+
## With the CLI
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pixel-vibing-cli generate vfx --preset <preset> [--subject <image id>] [--out <folder>] --yes --json
|
|
18
|
+
pixel-vibing-cli generate vfx --part <part>[,colour=<ramp>][,size=<n>][,start=<0-1>][,end=<0-1>] --part <part> … [--subject <image id>] --yes --json
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Each writes the effect's frames, `frame-01.png` on, and `effect.json` — each frame's time in
|
|
22
|
+
milliseconds, the effect's size, the point it is anchored at and whether it loops — into
|
|
23
|
+
`pixelvibing/effects/`, or the folder `--out` names, once its job is done.
|
|
24
|
+
|
|
25
|
+
## With the MCP server
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{ "project": "<id>", "preset": "explosion", "max_percent": 30 }
|
|
29
|
+
{ "project": "<id>", "parts": [{ "part": "fire_blast", "colour": "frost" }, { "part": "shockwave_ring", "start": 0.1, "end": 0.6 }], "max_percent": 30 }
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
with the tool `generate_effect`. `get_job` follows the job and, once done, names its frames in
|
|
33
|
+
order, with each frame's time in `data.frames`.
|
|
34
|
+
|
|
35
|
+
## Choosing it
|
|
36
|
+
|
|
37
|
+
- **A preset** is a whole effect: `explosion`, `lightning_strike`, `portal`, `heal_pillar`,
|
|
38
|
+
`magic_circle`, `slash_arc`, `shield_bubble` and more. One preset, nothing else.
|
|
39
|
+
- **Parts** build one: one to six, such as `fire_blast` with `shockwave_ring` and `debris_burst`
|
|
40
|
+
for a big explosion. Each takes:
|
|
41
|
+
- `colour`: a ramp's name (arcane, blood, electric, fire, frost, holy, nature, poison, shadow,
|
|
42
|
+
smoke, water), or 2 to 12 colours dark to light, to match the game's palette; on the CLI,
|
|
43
|
+
colours are joined by `/`, as `colour=#1a0b2e/#7f3ffb/#e8d5ff`.
|
|
44
|
+
- `size`, `amount` and `speed`: 1 is the part as made.
|
|
45
|
+
- `start` and `end`: when it plays, as fractions of a one-shot — a flash at 0, the
|
|
46
|
+
shockwave from 0.1, debris from 0.15.
|
|
47
|
+
- **A subject** is a sprite the effect is drawn around, an image of the account's of at most
|
|
48
|
+
256 px a side: an aura, a shield, a heal on a character.
|
|
49
|
+
- **What it costs.** Every effect costs the same, a preset's or six parts'.
|
|
50
|
+
- **Where it goes.** The game plays the frames at their times, placed at the anchor; copy them
|
|
51
|
+
into the game's own folder when that is where the engine looks. Effects are not part of the
|
|
52
|
+
map, the export or the sealed container.
|