diff --git a/RGB.NET.Core/Effects/AbstractBrushEffect.cs b/RGB.NET.Core/Effects/AbstractBrushEffect.cs
new file mode 100644
index 0000000..12ef4e8
--- /dev/null
+++ b/RGB.NET.Core/Effects/AbstractBrushEffect.cs
@@ -0,0 +1,54 @@
+// ReSharper disable MemberCanBePrivate.Global
+
+namespace RGB.NET.Core
+{
+ ///
+ /// Represents a basic effect targeting an .
+ ///
+ public abstract class AbstractBrushEffect : IEffect
+ where T : IBrush
+ {
+ #region Properties & Fields
+
+ ///
+ public bool IsDone { get; protected set; }
+
+ ///
+ /// Gets the this effect is targeting.
+ ///
+ protected T Brush { get; set; }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ public abstract void Update(double deltaTime);
+
+ ///
+ public virtual bool CanBeAppliedTo(IBrush target)
+ {
+ return target is T;
+ }
+
+ ///
+ public virtual void OnAttach(IBrush target)
+ {
+ Brush = (T)target;
+ }
+
+ ///
+ public virtual void OnDetach(IBrush target)
+ {
+ Brush = default(T);
+ }
+
+ #endregion
+ }
+
+ ///
+ /// Represents a basic effect targeting an .
+ ///
+ public abstract class AbstractBrushEffect : AbstractBrushEffect
+ { }
+}
diff --git a/RGB.NET.Core/Effects/AbstractLedGroupEffect.cs b/RGB.NET.Core/Effects/AbstractLedGroupEffect.cs
new file mode 100644
index 0000000..2e2dcfe
--- /dev/null
+++ b/RGB.NET.Core/Effects/AbstractLedGroupEffect.cs
@@ -0,0 +1,56 @@
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable UnusedMember.Global
+
+namespace RGB.NET.Core
+{
+ ///
+ /// Represents a basic effect targeting an .
+ ///
+ public abstract class AbstractLedGroupEffect : IEffect
+ where T : ILedGroup
+ {
+ #region Properties & Fields
+
+ ///
+ public bool IsDone { get; protected set; }
+
+ ///
+ /// Gets the this effect is targeting.
+ ///
+ protected T LedGroup { get; set; }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ public abstract void Update(double deltaTime);
+
+ ///
+ public virtual bool CanBeAppliedTo(ILedGroup target)
+ {
+ return target is T;
+ }
+
+ ///
+ public virtual void OnAttach(ILedGroup target)
+ {
+ LedGroup = (T)target;
+ }
+
+ ///
+ public virtual void OnDetach(ILedGroup target)
+ {
+ LedGroup = default(T);
+ }
+
+ #endregion
+ }
+
+ ///
+ /// Represents a basic effect targeting an .
+ ///
+ public abstract class AbstractLedGroupEffect : AbstractLedGroupEffect
+ { }
+}
diff --git a/RGB.NET.Core/RGB.NET.Core.csproj b/RGB.NET.Core/RGB.NET.Core.csproj
index 297a8d3..f219385 100644
--- a/RGB.NET.Core/RGB.NET.Core.csproj
+++ b/RGB.NET.Core/RGB.NET.Core.csproj
@@ -51,7 +51,9 @@
+
+
diff --git a/RGB.NET.Effects/Effects/FlashEffect.cs b/RGB.NET.Effects/Effects/FlashEffect.cs
new file mode 100644
index 0000000..daab23a
--- /dev/null
+++ b/RGB.NET.Effects/Effects/FlashEffect.cs
@@ -0,0 +1,153 @@
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedMember.Global
+
+using System;
+using RGB.NET.Core;
+
+namespace RGB.NET.Effects
+{
+ ///
+ /// Represents an effect which allows to flash an brush by modifying his opacity.
+ ///
+ public class FlashEffect : AbstractBrushEffect
+ {
+ #region Properties & Fields
+
+ ///
+ /// Gets or sets the attack-time (in seconds) of the effect. (default: 0.2)
+ /// This is close to a synthesizer envelope. (See as reference)
+ ///
+ public double Attack { get; set; } = 0.2;
+
+ ///
+ /// Gets or sets the decay-time (in seconds) of the effect. (default: 0)
+ /// This is close to a synthesizer envelope. (See as reference)
+ ///
+ public double Decay { get; set; } = 0;
+
+ ///
+ /// Gets or sets the sustain-time (in seconds) of the effect. (default: 0.3)
+ /// This is close to a synthesizer envelope. (See as reference)
+ /// Note that this value for naming reasons represents the time NOT the level.
+ ///
+ public double Sustain { get; set; } = 0.3;
+
+ ///
+ /// Gets or sets the release-time (in seconds) of the effect. (default: 0.2)
+ /// This is close to a synthesizer envelope. (See as reference)
+ ///
+ public double Release { get; set; } = 0.2;
+
+ ///
+ /// Gets or sets the level to which the oppacity (percentage) should raise in the attack-cycle. (default: 1);
+ ///
+ public double AttackValue { get; set; } = 1;
+
+ ///
+ /// Gets or sets the level at which the oppacity (percentage) should stay in the sustain-cycle. (default: 1);
+ ///
+ public double SustainValue { get; set; } = 1;
+
+ ///
+ /// Gets or sets the interval (in seconds) in which the effect should repeat (if repetition is enabled). (default: 1)
+ ///
+ public double Interval { get; set; } = 1;
+
+ ///
+ /// Gets or sets the amount of repetitions the effect should do until it's finished. Zero means infinite. (default: 0)
+ ///
+ public int Repetitions { get; set; } = 0;
+
+ private ADSRPhase _currentPhase;
+ private double _currentPhaseValue;
+ private int _repetitionCount;
+
+ #endregion
+
+ #region Methods
+
+ ///
+ public override void Update(double deltaTime)
+ {
+ _currentPhaseValue -= deltaTime;
+
+ // Using ifs instead of a switch allows to skip phases with time 0.
+ // ReSharper disable InvertIf
+
+ if (_currentPhase == ADSRPhase.Attack)
+ if (_currentPhaseValue > 0)
+ Brush.Opacity = Math.Min(1, (Attack - _currentPhaseValue) / Attack) * AttackValue;
+ else
+ {
+ _currentPhaseValue = Decay;
+ _currentPhase = ADSRPhase.Decay;
+ }
+
+ if (_currentPhase == ADSRPhase.Decay)
+ if (_currentPhaseValue > 0)
+ Brush.Opacity = SustainValue + (Math.Min(1, _currentPhaseValue / Decay) * (AttackValue - SustainValue));
+ else
+ {
+ _currentPhaseValue = Sustain;
+ _currentPhase = ADSRPhase.Sustain;
+ }
+
+ if (_currentPhase == ADSRPhase.Sustain)
+ if (_currentPhaseValue > 0)
+ Brush.Opacity = SustainValue;
+ else
+ {
+ _currentPhaseValue = Release;
+ _currentPhase = ADSRPhase.Release;
+ }
+
+ if (_currentPhase == ADSRPhase.Release)
+ if (_currentPhaseValue > 0)
+ Brush.Opacity = Math.Min(1, _currentPhaseValue / Release) * SustainValue;
+ else
+ {
+ _currentPhaseValue = Interval;
+ _currentPhase = ADSRPhase.Pause;
+ }
+
+ if (_currentPhase == ADSRPhase.Pause)
+ if (_currentPhaseValue > 0)
+ Brush.Opacity = 0;
+ else
+ {
+ if ((++_repetitionCount >= Repetitions) && (Repetitions > 0))
+ IsDone = true;
+ _currentPhaseValue = Attack;
+ _currentPhase = ADSRPhase.Attack;
+ }
+
+ // ReSharper restore InvertIf
+ }
+
+ ///
+ /// Resets the effect.
+ ///
+ public override void OnAttach(IBrush brush)
+ {
+ base.OnAttach(brush);
+
+ _currentPhase = ADSRPhase.Attack;
+ _currentPhaseValue = Attack;
+ _repetitionCount = 0;
+ brush.Opacity = 0;
+ }
+
+ #endregion
+
+ // ReSharper disable once InconsistentNaming
+ private enum ADSRPhase
+ {
+ Attack,
+ Decay,
+ Sustain,
+ Release,
+ Pause
+ }
+ }
+}
diff --git a/RGB.NET.Effects/Effects/MoveGradientEffect.cs b/RGB.NET.Effects/Effects/MoveGradientEffect.cs
new file mode 100644
index 0000000..92452e8
--- /dev/null
+++ b/RGB.NET.Effects/Effects/MoveGradientEffect.cs
@@ -0,0 +1,101 @@
+using RGB.NET.Brushes;
+using RGB.NET.Brushes.Gradients;
+using RGB.NET.Core;
+
+namespace RGB.NET.Effects
+{
+ ///
+ /// Represents an effect which allows to move an by modifying his offset.
+ ///
+ public class MoveGradientEffect : AbstractBrushEffect
+ {
+ #region Properties & Fields
+ // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+ // ReSharper disable MemberCanBePrivate.Global
+
+ ///
+ /// Gets or sets the direction the is moved.
+ /// True leads to an offset-increment (normaly moving to the right), false to an offset-decrement (normaly moving to the left).
+ ///
+ public bool Direction { get; set; }
+
+ ///
+ /// Gets or sets the speed of the movement in units per second.
+ /// The meaning of units differs for the different , but 360 units will always be one complete cycle:
+ /// : 360 unit = 1 offset.
+ /// : 1 unit = 1 degree.
+ ///
+ public double Speed { get; set; }
+
+ // ReSharper restore MemberCanBePrivate.Global
+ // ReSharper restore AutoPropertyCanBeMadeGetOnly.Global
+ #endregion
+
+ #region Constructors
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public MoveGradientEffect(double speed = 180.0, bool direction = true)
+ {
+ this.Speed = speed;
+ this.Direction = direction;
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ public override void Update(double deltaTime)
+ {
+ double movement = Speed * deltaTime;
+
+ if (!Direction)
+ movement = -movement;
+
+ // ReSharper disable once CanBeReplacedWithTryCastAndCheckForNull
+ if (Brush.Gradient is LinearGradient)
+ {
+ LinearGradient linearGradient = (LinearGradient)Brush.Gradient;
+
+ movement /= 360.0;
+
+ foreach (GradientStop gradientStop in linearGradient.GradientStops)
+ {
+ gradientStop.Offset = gradientStop.Offset + movement;
+
+ if (gradientStop.Offset > 1)
+ gradientStop.Offset -= 1;
+ else if (gradientStop.Offset < 0)
+ gradientStop.Offset += 1;
+ }
+ }
+ else if (Brush.Gradient is RainbowGradient)
+ {
+ RainbowGradient rainbowGradient = (RainbowGradient)Brush.Gradient;
+
+ // RainbowGradient is calculated inverse but the movement should be the same for all.
+ movement *= -1;
+
+ rainbowGradient.StartHue += movement;
+ rainbowGradient.EndHue += movement;
+
+ if ((rainbowGradient.StartHue > 360) && (rainbowGradient.EndHue > 360))
+ {
+ rainbowGradient.StartHue -= 360;
+ rainbowGradient.EndHue -= 360;
+ }
+ else if ((rainbowGradient.StartHue < -360) && (rainbowGradient.EndHue < -360))
+ {
+ rainbowGradient.StartHue += 360;
+ rainbowGradient.EndHue += 360;
+ }
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/RGB.NET.Effects/RGB.NET.Effects.csproj b/RGB.NET.Effects/RGB.NET.Effects.csproj
index 4a65052..78143b9 100644
--- a/RGB.NET.Effects/RGB.NET.Effects.csproj
+++ b/RGB.NET.Effects/RGB.NET.Effects.csproj
@@ -31,6 +31,14 @@
4
+
+ ..\packages\RGB.NET.Brushes.1.0.0\lib\net45\RGB.NET.Brushes.dll
+ True
+
+
+ ..\packages\RGB.NET.Core.1.0.0\lib\net45\RGB.NET.Core.dll
+ True
+
@@ -41,8 +49,13 @@
+
+
+
+
+