diff --git a/client/src/components/animations.jsx b/client/src/components/animations.jsx
index c3cdf40d..daa4f837 100644
--- a/client/src/components/animations.jsx
+++ b/client/src/components/animations.jsx
@@ -12,6 +12,7 @@ const Buff = require('./anims/buff');
const Debuff = require('./anims/debuff');
const Decay = require('./anims/decay');
const Curse = require('./anims/curse');
+const Electrify = require('./anims/electrify');
const Haste = require('./anims/haste');
const Stun = require('./anims/stun');
const Heal = require('./anims/heal');
@@ -101,6 +102,7 @@ function animations(props) {
case 'Block': return ;
case 'Buff': return ;
case 'Curse': return ;
+ case 'Electrify': return ;
case 'Blast': return ;
case 'Debuff': return ;
case 'Decay': return ;
diff --git a/client/src/components/anims/electrify.jsx b/client/src/components/anims/electrify.jsx
new file mode 100644
index 00000000..18c676ee
--- /dev/null
+++ b/client/src/components/anims/electrify.jsx
@@ -0,0 +1,102 @@
+const preact = require('preact');
+const { Component } = require('preact');
+const times = require('lodash/times')
+
+const anime = require('animejs').default;
+
+const { TIMES } = require('../../constants');
+
+// shamelessly lifted from teh anime docs
+// https://animejs.com/documentation/#svgAttr
+
+class Electrify extends Component {
+ constructor() {
+ super();
+ this.animations = [];
+ }
+
+ render() {
+ return (
+
+ );
+ }
+
+ componentDidMount() {
+ this.animations.push(anime({
+ targets: ['#electrify'],
+ opacity: [
+ { value: 1, delay: TIMES.TARGET_FADE_IN_DELAY, duration: TIMES.TARGET_FADE_IN_DURATION },
+ { value: 0, delay: TIMES.TARGET_FADE_OUT_DELAY, duration: TIMES.FADE_OUT_DURATION },
+ ],
+ easing: 'easeInOutSine',
+ }));
+
+ const path = () => `M10,64
+ L10,${anime.random(34, 94)}
+ L20,${anime.random(34, 94)}
+ L30,${anime.random(34, 94)}
+ L40,${anime.random(34, 94)}
+ L50,${anime.random(34, 94)}
+ L60,${anime.random(34, 94)}
+ L70,${anime.random(34, 94)}
+ L80,${anime.random(34, 94)}
+ L90,${anime.random(34, 94)}
+ L100,${anime.random(34, 94)}
+ L110,64
+ `;
+
+ this.animations.push(anime({
+ targets: ['#electrify path'],
+ d: times(10, path),
+ easing: 'easeOutExpo',
+ loop: true,
+ duration: TIMES.TARGET_MAIN_DURATION / 5,
+ }));
+
+ this.animations.push(anime({
+ targets: ['#electrify path.white'],
+ strokeWidth: [2, 1],
+ easing: 'easeInOutSine',
+ direction: 'alternate',
+ loop: true,
+ duration: TIMES.TARGET_MAIN_DURATION,
+ }));
+ }
+
+ // this is necessary because
+ // skipping / timing / unmounting race conditions
+ // can cause the animations to cut short, this will ensure the values are reset
+ // because preact will recycle all these components
+ componentWillUnmount() {
+ for (let i = this.animations.length - 1; i >= 0; i--) {
+ this.animations[i].reset();
+ }
+ }
+}
+
+module.exports = Electrify;