Here is some complex animation made with apel. Unlike most showcases this one uses a whole bunch of features
ParticleSphere sphere = new ParticleSphere(ParticleTypes.FLAME, 2f, 300);
sphere.setBeforeDraw(((data, obj) -> {
obj.setRadius(1.001f + ((float) Math.sin(0.1f * data.getCurrentStep())));
}));
ParticleSphere sphere2 = new ParticleSphere(sphere);
sphere2.setParticleEffect(ParticleTypes.SOUL_FIRE_FLAME);
Vector3f pos = world.getPlayers().getFirst().getPos().toVector3f();
float pi = (float) Math.PI;
CircularAnimator animator1 = new CircularAnimator(
1, 5f, pos, new Vector3f(pi, 0, 0), sphere, 500
);
CircularAnimator animator2 = new CircularAnimator(animator1);
animator2.setClockwise();
animator2.rotate(pi, pi, 0);
animator2.setParticleObject(sphere2);
ParallelAnimator parallelAnimator = new ParallelAnimator(1, animator1, animator2);
List<ParticleCylinder> cylinders = new ArrayList<>();
int maxAmount = 6;
for (int i = 0; i < maxAmount; i++) {
ParticleCylinder cylinder = new ParticleCylinder(
ParticleTypes.END_ROD, 0.01f, 2f, new Vector3f(0, pi * i / maxAmount, 0), 500
);
int finalI = i;
cylinder.setBeforeDraw((data, obj) -> {
float speed = (float) Math.sqrt(data.getCurrentStep() * finalI);
if (speed >= 20) return;
obj.setRadius(speed / 2);
int signedOne = obj.getRotation().y < 0 ? -1 : 1;
obj.setRotation(new Vector3f(0, signedOne * speed / 10, 0));
});
ParticleCylinder cylinder2 = new ParticleCylinder(cylinder);
cylinder2.setRotation(cylinder2.getRotation().mul(1f, -1f, 1f));
cylinders.add(cylinder);
cylinders.add(cylinder2);
}
ParticleCombiner<ParticleCylinder> cylinderCombiner = new ParticleCombiner<>(cylinders);
PointAnimator pointAnimator = new PointAnimator(1, cylinderCombiner, pos, 200);
SequentialAnimator sequentialAnimator = new SequentialAnimator(1, parallelAnimator, pointAnimator);
sequentialAnimator.beginAnimation(ApelRenderer.client(world));