Content generated with AI — it may contain mistakes.

Configuring

Animations

The seven animation types, the options each one reads, the twenty-one presets in animations.yml, and how frames stay in step.

An animation makes a skin's colour move. The trim, the name, the lore and the durability never change with it.

animations.yml
animations:
  inferno:
    type: frames
    interval: 0.1
    colors: ['#3a0000', '#c81d00', '#ff7a00', '#ffd000', '#ff7a00', '#c81d00']
    options:
      steps: '6'
KeyWhat it is
typerainbow, pulse, frames, or a type another plugin registered.
intervalSeconds between frames. Converted to ticks and never below one tick.
colorsHex colours the type works with. What they mean depends on the type.
optionsFree-form per-type values, written as text.

A skin then names it:

skins.yml
skins:
  inferno:
    animation: inferno
A bare type works too

animation: rainbow with no matching preset falls back to the type with its defaults — an interval of two ticks, no colours, no options. That is why rainbow works before anybody has opened animations.yml.

The seven types

rainbow

Walks the hue circle. Ignores colors and the skin's own colour.

OptionDefaultEffect
step10Degrees of hue per frame. Lower is slower and smoother.
saturation1.00 – 1. Lower washes the colours out.
brightness1.00 – 1. Lower darkens them.

pulse

Breathes from a rest colour to a peak and back.

OptionDefaultEffect
length40Frames for a full there-and-back. Minimum 2.

The first entry in colors is the rest colour; with none, the skin's own color is used, and with neither, black. The second entry is the peak; with none, white.

frames

Cycles through colors in order.

OptionDefaultEffect
smoothtrueBlends between neighbouring colours instead of jumping.
steps10Frames spent blending from one colour to the next. Only read when smooth is on.

With smooth: 'false' each frame is one colour from the list. With one colour it holds that colour; with none it leaves the skin's own colour alone.

The four that read the body

wave, sweep, bloom and flicker know which piece they are painting, so the animation travels across the set instead of playing the same frame on all four. A skin that fits one piece looks the same as it always did; a full set is where they show.

TypeWhat it doesOptions
waveThe colour rolls up or down the body, one piece behind the next.length (40 frames), spread (0.25), direction (up / down)
sweepA band of light crosses the body once per pass, then the set rests dark.length (40), width (0.45), hold (0), direction
bloomA pulse opens out of one piece; its neighbours follow a beat later.origin (chestplate), length (40), delay (6), width (14)
flickerSparks catch one piece at a time. sync: true flashes all four together.chance (0.18), hold (2), sync (false)

pulse, sweep, bloom and flicker read the first colour as the resting one and the second as the one they reach for; frames and wave cycle through all of them.

Turning the metal in a trim

Any type can also cycle the trim's material while the leather keeps its own animation. The pattern never changes — only the metal in it.

prismatic:
  type: sweep
  colors: ['#1b1035', '#c77dff']
  options:
    materials: 'amethyst,diamond,gold,netherite'
    trim-hold: 10
    trim-spread: 3
OptionDefaultWhat it does
materials—The trim materials it turns through, in order. Without it nothing about the trim moves.
trim-hold10Frames each material is held for.
trim-spread0Frames of offset between one piece and the next, so the metal reaches the helmet after the boots.

It needs a skin with a trim-pattern and a trim-material. On a skin without one the leather still animates, no trim appears, and nothing is reported: a trim cycle on a skin that has no trim is a setting with nothing to do, not an error.

The twenty-one presets

PresetTypeIntervalOptionsColours
rainbowrainbow0.1 sstep: 8—
rainbow_slowrainbow0.25 sstep: 4—
pastelrainbow0.15 sstep: 6, saturation: 0.45—
heartbeatpulse0.05 slength: 24#7a0010 → #ff2a4d
toxicpulse0.1 slength: 30#0b1f0b → #5dff3a
emberpulse0.1 slength: 40#2b0a00 → #ff5a00
shogunpulse0.08 slength: 32#1a0000 → #c8102e
bloodmoonpulse0.1 slength: 36#2a0000 → #a3001b
infernoframes0.1 ssteps: 6six reds and oranges
oceanframes0.15 ssteps: 8six blues
galaxyframes0.15 ssteps: 8five purples and pinks
auroraframes0.2 ssteps: 10five greens, cyans and violets
voltageframes0.08 ssmooth: falsefour blues and white, switched hard
tempestframes0.12 ssteps: 8five greys and pale blues
sakuraframes0.2 ssteps: 10five pinks
dragonfireframes0.1 ssteps: 6five embers
void_dragonframes0.18 ssteps: 8five violets
frostbiteframes0.2 ssteps: 10four ice blues
neonframes0.1 ssteps: 6four neons
verdantframes0.25 ssteps: 10five greens
celestialframes0.2 ssteps: 10four golds

Every shipped skin points at the preset of the same name.

Everyone is on the same frame

The frame number comes from the server clock, not from a counter started when the piece was equipped:

frame = floor(currentTimeMillis / 50 / intervalTicks)

Two players wearing rainbow, one for an hour and one for a second, show the same colour at the same instant. Timers still run per player — that is what Folia requires — but the clock they read is shared.

What it costs

One repeating task per animated piece worn, and nothing at all for a still skin. A frame copies a protocol stack the plugin already holds, writes one colour component on it and re-sends that slot; a frame whose colour has not changed sends no packet. The task stops itself the moment the piece comes off, the skin changes, or the wearer leaves.

Unknown names are reported, not guessed

animation: sparkle with no such preset and no such type logs which presets and which types exist, and the skin loads as a still colour. The same happens to an entry in animations.yml whose type is unknown or missing.

Adding a type in code

A type is a factory from a spec to an animation, so another plugin can register one and then use it from YAML like any built-in. See API.

Something missing on this page? Tell us on Discord