diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index f6a2a0c2967226ebef3a81f9bee66f31cf56022d..52924bb3c97968fd14862821a1f3b12bf588b222 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -1353,7 +1353,13 @@ libqt_plugin_la_SHADER := shaders/FadingEdge.frag \
                           shaders/RectangularGlow.frag \
                           shaders/SDFAARoundedTexture.frag \
                           shaders/SDFAARoundedTexture_cropsupport.frag \
-                          shaders/DitheredTexture.frag
+                          shaders/DitheredTexture.frag \
+                          shaders/VideoProgressBar.frag
+
+shaders/SDFAARoundedTexture.frag: shaders/SDF.glsl
+shaders/SDFAARoundedTexture_cropsupport.frag: shaders/SDF.glsl
+shaders/VideoProgressBar.frag: shaders/SDF.glsl
+
 if ENABLE_QT
 
 libqt_plugin_la_LIBADD += libqml_module_dialogs.a \
@@ -1407,7 +1413,7 @@ QSB_PARAMS_VERBOSE_ = $(QSB_PARAMS_VERBOSE__$(AM_DEFAULT_VERBOSITY))
 QSB_PARAMS_VERBOSE_0 = -s
 QSB_PARAMS_VERBOSE__0 = $(QSB_PARAMS_VERBOSE_0)
 
-EXTRA_DIST += shaders/Common.glsl
+EXTRA_DIST += shaders/Common.glsl shaders/SDF.glsl
 
 %.frag.qsb: %.frag shaders/Common.glsl
 	$(qsb_verbose)PATH="$(QSB_EXTRA_PATH)$$PATH" $(QSB) $(QSB_PARAMS) $(QSB_PARAMS_VERBOSE) -o $@ $<
diff --git a/modules/gui/qt/medialibrary/qml/VideoGridItem.qml b/modules/gui/qt/medialibrary/qml/VideoGridItem.qml
index 9730d652a629ecea93c13c16c7c4db20c9a3caef..e286fd990de52996627340eec828efa877076c77 100644
--- a/modules/gui/qt/medialibrary/qml/VideoGridItem.qml
+++ b/modules/gui/qt/medialibrary/qml/VideoGridItem.qml
@@ -88,7 +88,7 @@ Widgets.GridItem {
 
             visible: (model.progress > 0)
 
-            radius: root.pictureRadius
+            radius: root.effectiveRadius
             value: Helpers.clamp(model.progress !== undefined ? model.progress : 0, 0, 1)
         }
     }
diff --git a/modules/gui/qt/network/qml/NetworkGridItem.qml b/modules/gui/qt/network/qml/NetworkGridItem.qml
index 1e9fe8ece5d126a053689a0372134ad8cf2aa5e7..1837abc8d67e5a9f189a1e98d87acc172e479249 100644
--- a/modules/gui/qt/network/qml/NetworkGridItem.qml
+++ b/modules/gui/qt/network/qml/NetworkGridItem.qml
@@ -85,7 +85,7 @@ Widgets.GridItem {
 
             visible: (model.progress ?? - 1) > 0
 
-            radius: root.pictureRadius
+            radius: root.effectiveRadius
             value:  visible
                     ? Helpers.clamp(model.progress, 0, 1)
                     : 0
diff --git a/modules/gui/qt/shaders/SDF.glsl b/modules/gui/qt/shaders/SDF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..e8f69e44aa2fa1d57e6963bc4166f5c17e075c7b
--- /dev/null
+++ b/modules/gui/qt/shaders/SDF.glsl
@@ -0,0 +1,27 @@
+/*****************************************************************************
+ * Copyright (C) 2015 Inigo Quilez
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the “Software”), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *****************************************************************************/
+
+// Signed distance function by Inigo Quilez (https://iquilezles.org/articles/distfunctions2d)
+// b.x = width
+// b.y = height
+// r.x = roundness top-right
+// r.y = roundness boottom-right
+// r.z = roundness top-left
+// r.w = roundness bottom-left
+float sdRoundBox( in vec2 p, in vec2 b, in vec4 r )
+{
+    r.xy = (p.x>0.0)?r.xy : r.zw;
+    r.x  = (p.y>0.0)?r.x  : r.y;
+    vec2 q = abs(p)-b+r.x;
+    return min(max(q.x,q.y),0.0) + length(max(q,0.0)) - r.x;
+}
diff --git a/modules/gui/qt/shaders/SDFAARoundedTexture.frag b/modules/gui/qt/shaders/SDFAARoundedTexture.frag
index 88438b601ba273367aa1307a17e7cce64c0ccfd2..ae18ef833c4a00ce6d509640dd483cd90b99e79a 100644
--- a/modules/gui/qt/shaders/SDFAARoundedTexture.frag
+++ b/modules/gui/qt/shaders/SDFAARoundedTexture.frag
@@ -22,18 +22,9 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-/*****************************************************************************
- * Copyright (C) 2015 Inigo Quilez
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the “Software”), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is furnished
- * to do so, subject to the following conditions:
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *****************************************************************************/
+#extension GL_GOOGLE_include_directive : enable
+
+#include "SDF.glsl"
 
 layout(location = 0) in vec2 qt_TexCoord0;
 
@@ -62,21 +53,6 @@ layout(std140, binding = 0) uniform buf {
 
 layout(binding = 1) uniform sampler2D source;
 
-// Signed distance function by Inigo Quilez (https://iquilezles.org/articles/distfunctions2d)
-// b.x = width
-// b.y = height
-// r.x = roundness top-right
-// r.y = roundness boottom-right
-// r.z = roundness top-left
-// r.w = roundness bottom-left
-float sdRoundBox( in vec2 p, in vec2 b, in vec4 r )
-{
-    r.xy = (p.x>0.0)?r.xy : r.zw;
-    r.x  = (p.y>0.0)?r.x  : r.y;
-    vec2 q = abs(p)-b+r.x;
-    return min(max(q.x,q.y),0.0) + length(max(q,0.0)) - r.x;
-}
-
 void main()
 {
     // The signed distance function works when the primitive is centered.
diff --git a/modules/gui/qt/shaders/SDFAARoundedTexture_cropsupport.frag b/modules/gui/qt/shaders/SDFAARoundedTexture_cropsupport.frag
index f3ba567bc40b42c415b6a265166c3497f101a304..803e37cdd8fc34da4a9cf069e490a7a0a40998cc 100644
--- a/modules/gui/qt/shaders/SDFAARoundedTexture_cropsupport.frag
+++ b/modules/gui/qt/shaders/SDFAARoundedTexture_cropsupport.frag
@@ -34,18 +34,9 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-/*****************************************************************************
- * Copyright (C) 2015 Inigo Quilez
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the “Software”), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is furnished
- * to do so, subject to the following conditions:
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *****************************************************************************/
+#extension GL_GOOGLE_include_directive : enable
+
+#include "SDF.glsl"
 
 layout(location = 0) in vec2 qt_TexCoord0;
 
@@ -74,21 +65,6 @@ layout(std140, binding = 0) uniform buf {
 
 layout(binding = 1) uniform sampler2D source;
 
-// Signed distance function by Inigo Quilez (https://iquilezles.org/articles/distfunctions2d)
-// b.x = width
-// b.y = height
-// r.x = roundness top-right
-// r.y = roundness boottom-right
-// r.z = roundness top-left
-// r.w = roundness bottom-left
-float sdRoundBox( in vec2 p, in vec2 b, in vec4 r )
-{
-    r.xy = (p.x>0.0)?r.xy : r.zw;
-    r.x  = (p.y>0.0)?r.x  : r.y;
-    vec2 q = abs(p)-b+r.x;
-    return min(max(q.x,q.y),0.0) + length(max(q,0.0)) - r.x;
-}
-
 void main()
 {
     // The signed distance function works when the primitive is centered.
diff --git a/modules/gui/qt/shaders/VideoProgressBar.frag b/modules/gui/qt/shaders/VideoProgressBar.frag
new file mode 100644
index 0000000000000000000000000000000000000000..a256e47cbb1a6f4a1c634362a861e4cddcce49bd
--- /dev/null
+++ b/modules/gui/qt/shaders/VideoProgressBar.frag
@@ -0,0 +1,75 @@
+#version 440
+
+#define ANTIALIASING
+
+/*****************************************************************************
+ * Copyright (C) 2025 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * ( at your option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#extension GL_GOOGLE_include_directive : enable
+
+#include "SDF.glsl"
+
+layout(location = 0) out vec4 fragColor;
+
+// NOTE: Even though there is no texture, `qt_TexCoord0` is still provided.
+//       This is useful, because we don't need to normalize ourselves from
+//       gl_FragCoord using qt_Matrix and viewport size. As there is no
+//       texture sampler, this is always in normal form (no need to care
+//       about the texture atlas):
+layout(location = 0) in vec2 qt_TexCoord0;
+
+layout(std140, binding = 0) uniform buf {
+    mat4 qt_Matrix;
+    float qt_Opacity;
+
+    float progress;
+    float radius;
+
+    vec2 size;
+
+    vec4 elapsedColor;
+    vec4 remainingColor;
+};
+
+void main()
+{
+    vec2 p = (size.xy * ((2.0 * qt_TexCoord0) - 1)) / size.y;
+
+    // Signed distance:
+    // TODO: Round box distance function may be reducted when radius for top left and top right are always infinite.
+    float dist = sdRoundBox(p, vec2(size.x / size.y, 1.0), vec4(radius, 999., radius, 999.));
+
+    vec4 color = (qt_TexCoord0.x <= progress) ? elapsedColor : remainingColor;
+
+#ifdef ANTIALIASING
+    float softEdgeMax = fwidth(dist) * 0.75;
+    float softEdgeMin = -softEdgeMax;
+
+    // Soften the outline, as recommended by the Valve paper, using smoothstep:
+    // "Improved Alpha-Tested Magnification for Vector Textures and Special Effects"
+    // NOTE: The whole texel is multiplied, because of premultiplied alpha.
+    float factor = smoothstep(softEdgeMin, softEdgeMax, dist);
+#else
+    float factor = step(0.0, dist);
+#endif
+
+    // NOTE: Colors are in premultiplied alpha format
+    color *= (1.0 - factor);
+
+    fragColor = color * qt_Opacity;
+}
diff --git a/modules/gui/qt/shaders/meson.build b/modules/gui/qt/shaders/meson.build
index b23d7fc9d014d13171737c54076d0ae8ab6f37c7..714b057cb08f82d400357b2b32f1a55290b65804 100644
--- a/modules/gui/qt/shaders/meson.build
+++ b/modules/gui/qt/shaders/meson.build
@@ -7,21 +7,23 @@ env = environment()
 env.append('PATH', contrib_dir + '/bin')
 
 shader_sources = [
-    'FadingEdge.frag',
-    'FadingEdgeX.vert',
-    'FadingEdgeY.vert',
-    'Noise.frag',
-    'RectFilter.frag',
-    'SubTexture.vert',
-    'PlayerBlurredBackground.frag',
-    'HollowRectangularGlow.frag',
-    'RectangularGlow.frag',
-    'SDFAARoundedTexture.frag',
-    'SDFAARoundedTexture_cropsupport.frag',
-    'DitheredTexture.frag'
+    {'shader': 'FadingEdge.frag', 'dependencies': []},
+    {'shader': 'FadingEdgeX.vert', 'dependencies': []},
+    {'shader': 'FadingEdgeY.vert', 'dependencies': []},
+    {'shader': 'Noise.frag', 'dependencies': []},
+    {'shader': 'RectFilter.frag', 'dependencies': []},
+    {'shader': 'SubTexture.vert', 'dependencies': []},
+    {'shader': 'PlayerBlurredBackground.frag', 'dependencies': []},
+    {'shader': 'HollowRectangularGlow.frag', 'dependencies': []},
+    {'shader': 'RectangularGlow.frag', 'dependencies': []},
+    {'shader': 'DitheredTexture.frag', 'dependencies': []},
+    {'shader': 'SDFAARoundedTexture.frag', 'dependencies': ['SDF.glsl']},
+    {'shader': 'SDFAARoundedTexture_cropsupport.frag', 'dependencies': ['SDF.glsl']},
+    {'shader': 'VideoProgressBar.frag', 'dependencies': ['SDF.glsl']},
 ]
 
-shader_files = files(shader_sources)
+# This is populated in the for-each loop below:
+shader_files = []
 
 qt_bin_directory = qt6_dep.get_variable(pkgconfig: 'bindir', configtool: 'QT_HOST_BINS')
 qsb = find_program('qsb', dirs: qt_bin_directory, required: true)
@@ -35,11 +37,14 @@ endif
 
 shader_targets = []
 foreach shader: shader_sources
-    shader_target_name = shader + '.qsb'
+    shader_file = shader['shader']
+    shader_files += files(shader_file)
+
+    shader_target_name = shader_file + '.qsb'
 
     target = custom_target(shader_target_name,
-      depend_files: ['Common.glsl'],
-      input: shader,
+      depend_files: shader['dependencies'] + 'Common.glsl',
+      input: shader_file,
       output: shader_target_name,
       command: [qsb, qsb_params, '--output', '@OUTPUT@', '@INPUT@']
     )
diff --git a/modules/gui/qt/shaders/shaders.qrc b/modules/gui/qt/shaders/shaders.qrc
index 58f3ff53afec26ef30e05cdd6e8666e84dc7528c..5412a2b2966b230ba39f6db7908ca9b420940981 100644
--- a/modules/gui/qt/shaders/shaders.qrc
+++ b/modules/gui/qt/shaders/shaders.qrc
@@ -13,5 +13,6 @@
         <file alias="SDFAARoundedTexture.frag.qsb">SDFAARoundedTexture.frag.qsb</file>
         <file alias="SDFAARoundedTexture_cropsupport.frag.qsb">SDFAARoundedTexture_cropsupport.frag.qsb</file>
         <file alias="DitheredTexture.frag.qsb">DitheredTexture.frag.qsb</file>
+        <file alias="VideoProgressBar.frag.qsb">VideoProgressBar.frag.qsb</file>
     </qresource>
 </RCC>
diff --git a/modules/gui/qt/widgets/qml/VideoProgressBar.qml b/modules/gui/qt/widgets/qml/VideoProgressBar.qml
index f10918b3b32a75a17f087f82068ad1307dae7d96..e94953cf9b338867b35fb8f79c49f01a4b440308 100644
--- a/modules/gui/qt/widgets/qml/VideoProgressBar.qml
+++ b/modules/gui/qt/widgets/qml/VideoProgressBar.qml
@@ -24,21 +24,61 @@ import VLC.Style
 Item {
     id: progressBar
 
-    implicitHeight: VLCStyle.dp(4, VLCStyle.scale)
+    // Shader effect needs double height, but it does not paint anything in the upper half:
+    implicitHeight: VLCStyle.dp(4, VLCStyle.scale) * (shaderEffect.readyForVisibility ? 2.0 : 1.0)
 
-    clip :true
+    clip: !shaderEffect.readyForVisibility
 
     property real value: 0
-    property int radius: implicitHeight
+    property real radius: implicitHeight
+
+    property color elapsedColor: theme.fg.primary
+    //FIXME: do we want it always white or do we want it to change with the theme
+    property color remainingColor: "white"
 
     readonly property ColorContext colorContext: ColorContext {
         id: theme
         colorSet: ColorContext.Slider
     }
 
+    // WARNING: We can not override QQuickItem's antialiasing
+    //          property as readonly because Qt 6.6 marks it
+    //          as `FINAL`...
+    // FIXME: The shader can be generated without
+    //        the define that enables antialiasing.
+    //        It should be done when the build system
+    //        starts supporting shader defines.
+    antialiasing: true
+
+    ShaderEffect {
+        id: shaderEffect
+
+        anchors.fill: parent
+
+        antialiasing: progressBar.antialiasing
+
+        blending: radius > 0.0
+
+        cullMode: ShaderEffect.BackFaceCulling
+
+        readonly property double progress: progressBar.value
+        readonly property double radius: progressBar.radius / (height / 2)
+        readonly property size size: Qt.size(width, height)
+        readonly property color elapsedColor: progressBar.elapsedColor
+        readonly property color remainingColor: progressBar.remainingColor
+
+        visible: readyForVisibility
+
+        readonly property bool readyForVisibility: (GraphicsInfo.shaderType === GraphicsInfo.RhiShader)
+
+        fragmentShader: "qrc:///shaders/VideoProgressBar.frag.qsb"
+    }
+
     Rectangle {
         id: rectangle
 
+        visible: !shaderEffect.readyForVisibility
+
         anchors.left: parent.left
         anchors.right: parent.right
         anchors.bottom: parent.bottom
@@ -46,13 +86,14 @@ Item {
         height: Math.max(progressBar.radius * 2, //to have at least the proper radius applied
                          parent.height + radius) //the top radius section should be always clipped
 
-        //FIXME do we want it always white or do we want it to change with the theme
-        color: "white"
+        color: progressBar.remainingColor
         radius: progressBar.radius
 
+        antialiasing: progressBar.antialiasing
+
         gradient: Gradient {
             orientation: Gradient.Horizontal
-            GradientStop { position: progressBar.value; color: theme.fg.primary }
+            GradientStop { position: progressBar.value; color: progressBar.elapsedColor }
             GradientStop { position: progressBar.value + (1. / rectangle.width); color: rectangle.color }
         }
     }