diff --git a/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/LinearFadeController.java b/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/LinearFadeController.java
new file mode 100644
index 0000000000000000000000000000000000000000..3287ca97157df9df9aac614b43ccd21baa49e94a
--- /dev/null
+++ b/PlayWallCore/src/main/java/de/tobias/playpad/pad/fade/LinearFadeController.java
@@ -0,0 +1,26 @@
+package de.tobias.playpad.pad.fade;
+
+import javafx.animation.Transition;
+
+/**
+ * A fade controller implementation, that handles fade scala linear.
+ *
+ * @author tobias
+ * @since 7.1.0
+ */
+public class LinearFadeController extends AbstractFadeController {
+
+	public LinearFadeController(FadeControllerDelegate fadeDelegate) {
+		super(fadeDelegate);
+	}
+
+	@Override
+	protected void interpolate(Transition transition, double frac, double from, double to) {
+		double diff = Math.abs(to - from);
+		if (from < to) { // Fade In
+			fadeDelegate.onFadeLevelChange(diff * frac);
+		} else { // Fade Out
+			fadeDelegate.onFadeLevelChange(from - (diff * frac));
+		}
+	}
+}
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/ContentPlayerViewController.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/ContentPlayerViewController.scala
index f24e07c07f97cc10b2c677d56974e8596c77b64b..90bc30425035955ac49b0833f9381792c7a1a7b4 100644
--- a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/ContentPlayerViewController.scala
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/ContentPlayerViewController.scala
@@ -45,6 +45,7 @@ class ContentPlayerViewController extends NVC {
 
 			val mediaView = mediaViews(mediaPlayer)
 			mediaView.setUserData(padIndex)
+			mediaView.setOpacity(1.0)
 
 			if (!getChildren.contains(mediaView)) {
 				val index = activePlayers.indexOf(padIndex)
@@ -58,6 +59,13 @@ class ContentPlayerViewController extends NVC {
 			}
 		}
 
+		def setFadeValue(mediaPlayer: MediaPlayer, value: Double): Unit ={
+			if (mediaViews.contains(mediaPlayer)) {
+				val mediaView = mediaViews(mediaPlayer)
+				mediaView.setOpacity(value)
+			}
+		}
+
 		def highlight(on: Boolean): Unit = {
 			if (on) {
 				setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)))
@@ -69,7 +77,7 @@ class ContentPlayerViewController extends NVC {
 		override def toString: String = f"MediaPlayerStack: ${getChildren.stream().map(view => f"MediaView: ${view.getUserData}").collect(Collectors.joining(", "))}"
 	}
 
-	private val mediaPlayers: ListBuffer[MediaPlayerStack] = ListBuffer.empty
+	private val mediaStacks: ListBuffer[MediaPlayerStack] = ListBuffer.empty
 
 	load("view", "PlayerView")
 	applyViewControllerToStage
@@ -89,7 +97,7 @@ class ContentPlayerViewController extends NVC {
 	}
 
 	def showMediaPlayer(padIndex: PadIndex, mediaPlayer: MediaPlayer, zones: Seq[PlayerInstance]): Unit = {
-		val iterator = this.mediaPlayers.iterator
+		val iterator = this.mediaStacks.iterator
 		while (iterator.hasNext) {
 			val mediaPlayerStack = iterator.next()
 			if (zones.contains(mediaPlayerStack.playerInstance)) {
@@ -99,7 +107,7 @@ class ContentPlayerViewController extends NVC {
 	}
 
 	def disconnectMediaPlayer(mediaPlayer: MediaPlayer, zones: Seq[PlayerInstance]): Unit = {
-		val iterator = this.mediaPlayers.iterator
+		val iterator = this.mediaStacks.iterator
 		while (iterator.hasNext) {
 			val mediaPlayerStack = iterator.next()
 			if (zones.contains(mediaPlayerStack.playerInstance)) {
@@ -112,10 +120,10 @@ class ContentPlayerViewController extends NVC {
 		val parent = getParent.asInstanceOf[Pane]
 		parent.getChildren.clear()
 
-		mediaPlayers.clear()
+		mediaStacks.clear()
 		configuration.instances.forEach(player => {
 			val mediaPlayerStack = new MediaPlayerStack(player)
-			mediaPlayers.addOne(mediaPlayerStack)
+			mediaStacks.addOne(mediaPlayerStack)
 			parent.getChildren.add(mediaPlayerStack)
 		})
 
@@ -134,15 +142,24 @@ class ContentPlayerViewController extends NVC {
 		})
 	}
 
-	def addActivePadToList(padIndex: PadIndex, zones: Seq[PlayerInstance]): Unit = mediaPlayers
-		.filter(mediaPlayer => zones.contains(mediaPlayer.playerInstance))
-		.foreach(mediaPlayer => mediaPlayer.addActivePad(padIndex))
+	def addActivePadToList(padIndex: PadIndex, zones: Seq[PlayerInstance]): Unit = getMediaStacks(zones)
+		.foreach(mediaStack => mediaStack.addActivePad(padIndex))
 
-	def removeActivePadFromList(padIndex: PadIndex, zones: Seq[PlayerInstance]): Unit = mediaPlayers
-		.filter(mediaPlayer => zones.contains(mediaPlayer.playerInstance))
-		.foreach(mediaPlayer => mediaPlayer.removeActivePad(padIndex))
+	def removeActivePadFromList(padIndex: PadIndex, zones: Seq[PlayerInstance]): Unit = getMediaStacks(zones)
+		.foreach(mediaStack => mediaStack.removeActivePad(padIndex))
 
 	def highlight(zone: PlayerInstance, on: Boolean): Unit = {
-		mediaPlayers.filter(mediaPlayer => zone == mediaPlayer.playerInstance).head.highlight(on)
+		getMediaStack(zone).head.highlight(on)
+	}
+
+	def setFadeValue(mediaPlayer: MediaPlayer, zones: Seq[PlayerInstance], value: Double): Unit = getMediaStacks(zones)
+		.foreach(mediaStack => mediaStack.setFadeValue(mediaPlayer, value))
+
+	private def getMediaStack(zone: PlayerInstance): ListBuffer[MediaPlayerStack] = {
+		getMediaStacks(List(zone))
+	}
+
+	private def getMediaStacks(zones: Seq[PlayerInstance]): ListBuffer[MediaPlayerStack] = {
+		mediaStacks.filter(mediaPlayer => zones.contains(mediaPlayer.playerInstance))
 	}
 }
diff --git a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContent.scala b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContent.scala
index 2a4248de50c6b5f50a797a9a8bb47b7e7234282b..005aad995945036e872e3e3d1001944ebbbf1321 100644
--- a/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContent.scala
+++ b/PlayWallPlugins/PlayWallPluginContentPlayer/src/main/scala/de/tobias/playpad/plugin/content/pad/ContentPlayerPadContent.scala
@@ -6,6 +6,7 @@ import java.util.stream.Collectors
 
 import de.tobias.playpad.pad.content.play.{Durationable, Pauseable}
 import de.tobias.playpad.pad.content.{PadContent, Playlistable}
+import de.tobias.playpad.pad.fade.{Fadeable, LinearFadeController}
 import de.tobias.playpad.pad.mediapath.MediaPath
 import de.tobias.playpad.pad.{Pad, PadStatus}
 import de.tobias.playpad.plugin.content.ContentPluginMain
@@ -21,7 +22,7 @@ import javafx.util.Duration
 
 import scala.jdk.CollectionConverters._
 
-class ContentPlayerPadContent(val pad: Pad, val `type`: String) extends PadContent(pad) with Pauseable with Durationable with Playlistable {
+class ContentPlayerPadContent(val pad: Pad, val `type`: String) extends PadContent(pad) with Pauseable with Durationable with Playlistable with Fadeable {
 
 	private class MediaPlayerContainer(val path: MediaPath, val mediaPlayer: MediaPlayer) {
 		def play(): Unit = {
@@ -32,6 +33,8 @@ class ContentPlayerPadContent(val pad: Pad, val `type`: String) extends PadConte
 			mediaPlayer.seek(Duration.ZERO)
 			mediaPlayer.play()
 
+			getPad.setEof(false)
+
 			currentRunningIndexProperty.set(mediaPlayers.indexOf(this))
 
 			val controller = getPad.getController
@@ -84,6 +87,9 @@ class ContentPlayerPadContent(val pad: Pad, val `type`: String) extends PadConte
 	private var showingLastFrame: Boolean = false
 	private var isPause: Boolean = false
 
+	private val fadeController = new LinearFadeController(value => ContentPluginMain.playerViewController
+			.setFadeValue(mediaPlayers(currentPlayingMediaIndex).mediaPlayer, getSelectedZones, value))
+
 	override def getType: String = `type`
 
 	override def currentPlayingMediaIndex: Int = currentRunningIndexProperty.get()
@@ -128,7 +134,10 @@ class ContentPlayerPadContent(val pad: Pad, val `type`: String) extends PadConte
 	}
 
 	def onEof(): Unit = {
-		if (shouldShowLastFrame() && !showingLastFrame && !pad.getPadSettings.isLoop) {
+		if (shouldShowLastFrame() && !showingLastFrame // Only is settings is enabled and not already in last frame state
+			&& !pad.getPadSettings.isLoop // Only go to last frame state, is looping is disabled
+			&& !isFadeActive // Only go to last frame state, if no fade is active (if eof is reached while fade out, the last frame should not be hold)
+		) {
 			getPad.setStatus(PadStatus.PAUSE)
 			showingLastFrame = true
 			return
@@ -172,6 +181,36 @@ class ContentPlayerPadContent(val pad: Pad, val `type`: String) extends PadConte
 				.toArray(size => new Array[ReadOnlyObjectProperty[Duration]](size)): _*)
 	}
 
+	/*
+	Fadeable
+	 */
+
+	override def fadeIn(): Unit = {
+		val fadeIn = getPad.getPadSettings.getFade.getFadeIn
+		if (fadeIn.toMillis > 0) {
+			fadeController.fadeIn(fadeIn)
+		}
+	}
+
+	override def fadeOut(onFinish: Runnable): Unit = {
+		val fadeOut = getPad.getPadSettings.getFade.getFadeOut
+		if (fadeOut.toMillis > 0) {
+			fadeController.fadeOut(fadeOut, () => {
+				if (onFinish != null) onFinish.run()
+				updateVolume()
+			})
+		}
+		else {
+			onFinish.run()
+		}
+	}
+
+	override def isFadeActive: Boolean = fadeController.isFading
+
+	override def fade(from: Double, to: Double, duration: Duration, onFinish: Runnable): Unit = {
+		fadeController.fade(from, to, duration, onFinish)
+	}
+
 	/*
 	Loading
 	 */