FlutterFlow supports GPU visual effects through three routes: BackdropFilter for blur effects (no code needed), ShaderMask for gradient overlays (moderate complexity), and Flutter's FragmentProgram API for fully custom GLSL shaders (advanced). Start with BackdropFilter for frosted glass effects — it works in Run Mode with no export required.
GPU effects in Flutter — what FlutterFlow exposes
Shaders are programs that run on the GPU to calculate the color of each pixel on screen. Flutter exposes three levels of shader access. BackdropFilter is the simplest — it applies a pre-built blur or color matrix effect to whatever is behind a widget. ShaderMask applies a gradient shader to a child widget, useful for gradient text and image fades. FragmentProgram is the most powerful — it loads a custom GLSL (OpenGL Shading Language) file that you write, giving you per-pixel control for effects like ripples, heat distortion, and procedural animations. FlutterFlow's visual editor exposes BackdropFilter directly. ShaderMask and FragmentProgram require Custom Widgets, which need the Pro plan.
Prerequisites
- FlutterFlow project (BackdropFilter works on Free; Custom Widgets require Pro)
- Basic understanding of widgets and the FlutterFlow widget tree
- For GLSL shaders: familiarity with basic Dart code and Flutter widget lifecycle
- Pro plan for Custom Widget support (Custom Code → Custom Widgets)
Step-by-step guide
Add a frosted glass effect with BackdropFilter
Add a frosted glass effect with BackdropFilter
BackdropFilter is the easiest GPU effect and requires no code export. In FlutterFlow, select a Container widget that overlays an image or colorful background. Go to its properties → Background → enable Blur. Set the blur sigma value (10-15 gives a strong frosted glass look, 3-5 is subtle). Add a semi-transparent white fill (white, 30-40% opacity) to the container so the blur looks like frosted glass rather than just a smear. This is perfect for modal cards, navigation drawers, or hero banners overlaid on a background photo.
Expected result: A frosted glass card visible over a background image in Run Mode, with a smooth blur on all plans including Free.
Apply a gradient overlay with ShaderMask in a Custom Widget
Apply a gradient overlay with ShaderMask in a Custom Widget
ShaderMask applies a gradient that blends with a child widget's colors. Common uses: gradient text that fades from one color to another, images that fade to transparent at the bottom, and icon color transitions. Create a Custom Widget (Custom Code → Custom Widgets → Add Widget), name it 'GradientText'. Paste the code below. The widget wraps a Text child with a ShaderMask using a LinearGradient from your brand colors. After saving, drag the custom widget onto any page and set the text and gradient colors via its parameters.
1// Custom Widget: GradientText2import 'package:flutter/material.dart';34class GradientText extends StatelessWidget {5 const GradientText({6 super.key,7 required this.text,8 required this.style,9 required this.startColor,10 required this.endColor,11 });1213 final String text;14 final TextStyle style;15 final Color startColor;16 final Color endColor;1718 @override19 Widget build(BuildContext context) {20 return ShaderMask(21 blendMode: BlendMode.srcIn,22 shaderCallback: (Rect bounds) => LinearGradient(23 colors: [startColor, endColor],24 begin: Alignment.topLeft,25 end: Alignment.bottomRight,26 ).createShader(bounds),27 child: Text(text, style: style),28 );29 }30}Expected result: Text on your page renders with a smooth gradient from startColor to endColor, instead of a solid color.
Write a basic GLSL ripple shader and load it with FragmentProgram
Write a basic GLSL ripple shader and load it with FragmentProgram
FragmentProgram lets you write GLSL shaders that run entirely on the GPU. This is how you get effects like animated ripples, heat haze, or holographic shimmer. You need two files: the GLSL shader file (.frag) and a Custom Widget that loads it. First, export your FlutterFlow project (Pro plan required) to access the pubspec.yaml and assets folder. Add the shader file to an assets/shaders/ folder and register it in pubspec.yaml under flutter: shaders:. The Custom Widget loads it at runtime using FragmentProgram.fromAsset(). Paste the ripple shader code below.
1// assets/shaders/ripple.frag2#include <flutter/runtime_effect.glsl>34uniform float uTime;5uniform vec2 uCenter;6uniform sampler2D uTexture;78out vec4 fragColor;910void main() {11 vec2 fragCoord = FlutterFragCoord().xy;12 vec2 uv = fragCoord / vec2(400.0, 800.0);1314 float dist = distance(fragCoord, uCenter);15 float wave = sin(dist * 0.05 - uTime * 3.0) * 10.0;16 float strength = max(0.0, 1.0 - dist / 200.0);1718 vec2 offset = normalize(fragCoord - uCenter) * wave * strength * 0.005;19 fragColor = texture(uTexture, uv + offset);20}Expected result: After exporting and building the app natively, the ripple shader creates a water-distortion effect on the widget it wraps.
Load the FragmentProgram shader in a Custom Widget
Load the FragmentProgram shader in a Custom Widget
Now write the Dart Custom Widget that loads the .frag file at runtime and drives the animation with a Ticker. This widget uses AnimationController to update the uTime uniform every frame — the shader uses this value to animate the ripple wave. Add this as a Custom Widget in FlutterFlow or in your exported project. The widget wraps any child with the animated shader effect.
1// Custom Widget: RippleShaderWidget2import 'dart:ui' as ui;3import 'package:flutter/material.dart';4import 'package:flutter/scheduler.dart';56class RippleShaderWidget extends StatefulWidget {7 const RippleShaderWidget({super.key, required this.child});8 final Widget child;910 @override11 State<RippleShaderWidget> createState() => _RippleShaderWidgetState();12}1314class _RippleShaderWidgetState extends State<RippleShaderWidget>15 with SingleTickerProviderStateMixin {16 ui.FragmentProgram? _program;17 double _time = 0;18 late final Ticker _ticker;1920 @override21 void initState() {22 super.initState();23 _loadShader();24 _ticker = createTicker((elapsed) {25 setState(() => _time = elapsed.inMilliseconds / 1000.0);26 });27 _ticker.start();28 }2930 Future<void> _loadShader() async {31 final program = await ui.FragmentProgram.fromAsset('shaders/ripple.frag');32 if (mounted) setState(() => _program = program);33 }3435 @override36 void dispose() {37 _ticker.dispose();38 super.dispose();39 }4041 @override42 Widget build(BuildContext context) {43 if (_program == null) return widget.child;44 final shader = _program!.fragmentShader()45 ..setFloat(0, _time)46 ..setFloat(1, 200)47 ..setFloat(2, 400);48 return CustomPaint(49 painter: _ShaderPainter(shader),50 child: widget.child,51 );52 }53}5455class _ShaderPainter extends CustomPainter {56 _ShaderPainter(this.shader);57 final ui.FragmentShader shader;5859 @override60 void paint(Canvas canvas, Size size) {61 canvas.drawRect(Offset.zero & size, Paint()..shader = shader);62 }6364 @override65 bool shouldRepaint(_ShaderPainter old) => true;66}Expected result: The widget renders with an animated ripple distortion effect running at 60fps on physical devices.
Test shaders on device — not in web preview
Test shaders on device — not in web preview
GLSL shaders in Flutter have limited WebGL support. Some effects that work perfectly on iOS and Android will not render at all in the web browser — including the ripple FragmentProgram shader above. Always test shader effects using FlutterFlow's 'Run on Device' option (Scan QR code in Run Mode to open on a physical phone). BackdropFilter blur effects do work in web preview. For production apps, add a capability check and fall back to a simpler effect on web: check if the shader loaded successfully (program != null) and use a plain color if it didn't.
Expected result: Shader effects render correctly on iOS and Android physical devices. BackdropFilter effects also work in web preview.
Complete working example
1// FlutterFlow Custom Widget: GradientFadeImage2// Applies a bottom-to-transparent gradient fade over an image3// Works on all platforms including web4// Add as Custom Widget in FlutterFlow Custom Code section56import 'package:flutter/material.dart';78class GradientFadeImage extends StatelessWidget {9 const GradientFadeImage({10 super.key,11 required this.imageUrl,12 required this.height,13 required this.width,14 this.fadeColor = Colors.black,15 this.fadeFraction = 0.4,16 });1718 final String imageUrl;19 final double height;20 final double width;21 final Color fadeColor;22 final double fadeFraction; // 0.0 to 1.0 — how much of the image fades2324 @override25 Widget build(BuildContext context) {26 return SizedBox(27 height: height,28 width: width,29 child: ShaderMask(30 shaderCallback: (Rect bounds) {31 return LinearGradient(32 begin: Alignment.topCenter,33 end: Alignment.bottomCenter,34 colors: [35 Colors.white,36 Colors.white,37 Colors.transparent,38 ],39 stops: [0.0, 1.0 - fadeFraction, 1.0],40 ).createShader(bounds);41 },42 blendMode: BlendMode.dstIn,43 child: Image.network(44 imageUrl,45 height: height,46 width: width,47 fit: BoxFit.cover,48 errorBuilder: (context, error, stackTrace) => Container(49 color: Colors.grey[300],50 child: const Icon(Icons.broken_image, color: Colors.grey),51 ),52 ),53 ),54 );55 }56}Common mistakes
Why it's a problem: Writing complex GLSL and expecting it to work in Run Mode web preview
How to avoid: Always test GLSL shaders on a physical device via the QR code in Run Mode. For effects that need to work on web, use BackdropFilter or ShaderMask with LinearGradient, which are cross-platform.
Why it's a problem: Forgetting the #include <flutter/runtime_effect.glsl> header in shader files
How to avoid: Always start .frag files with #include <flutter/runtime_effect.glsl> and use FlutterFragCoord() instead of gl_FragCoord.
Why it's a problem: Using animated shaders on low-priority background elements
How to avoid: Limit animated shaders to small, isolated widgets. Use RepaintBoundary to isolate the shader widget so only it repaints each frame, not the whole page.
Why it's a problem: Not registering the .frag file in pubspec.yaml under flutter: shaders:
How to avoid: Add the shader path to pubspec.yaml: flutter: shaders: - assets/shaders/ripple.frag. Then run flutter pub get before building.
Best practices
- Start with BackdropFilter and ShaderMask before writing custom GLSL — they handle 80% of visual effects use cases
- Always test on physical devices for shader effects — web preview is unreliable for GPU features
- Wrap animated shader widgets in RepaintBoundary to prevent full-tree repaints
- Keep GLSL shaders to under 20 lines for mobile performance — complexity has a direct GPU cost
- Provide a non-shader fallback for web builds using platform detection (kIsWeb check)
- Use flutter_shaders package for asset management if you have more than 2-3 shader files
- Profile shader performance with Flutter DevTools' Performance overlay before shipping
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I'm building a Flutter app exported from FlutterFlow. I want to create a frosted glass card effect and a gradient text effect. Can you write: (1) a Flutter Custom Widget that uses BackdropFilter to create a frosted glass container with adjustable blur sigma and background opacity, and (2) a Custom Widget that uses ShaderMask with LinearGradient to render gradient-colored text? Both should accept colors and other properties as constructor parameters.
I have a FlutterFlow Pro account and want to add a gradient fade effect to images in my app — images should fade from full opacity to transparent at the bottom. How do I create this as a Custom Widget using ShaderMask and LinearGradient, and how do I add it to my FlutterFlow project as a reusable component with imageUrl and height as parameters?
Frequently asked questions
Do I need the Pro plan to use BackdropFilter blur effects?
No. BackdropFilter blur is available on all FlutterFlow plans through the Container widget's blur property. You only need the Pro plan for Custom Widgets, which are required for ShaderMask and FragmentProgram shaders.
Will custom GLSL shaders work on both iOS and Android?
Yes, on both platforms. Flutter uses Impeller (default on iOS and newer Android) which fully supports GLSL fragment shaders with the FragmentProgram API. Older Android devices using Skia may have minor rendering differences.
How do I animate a shader — for example, make a gradient slowly shift colors over time?
Pass a time uniform to the shader (setFloat(0, elapsedSeconds)). Use AnimationController or a Ticker in your Custom Widget to update the time value every frame and call setState. The shader receives the updated time and recalculates pixel colors for each frame.
Is there a performance difference between BackdropFilter and a custom GLSL shader?
BackdropFilter is highly optimized and uses a single platform-level call. Custom GLSL shaders run on the GPU but add draw call overhead and must compile at runtime. For simple effects, BackdropFilter is faster. For complex per-pixel effects that BackdropFilter can't replicate, GLSL is your only option.
Can I use a ShaderMask for a radial gradient instead of linear?
Yes. Replace LinearGradient with RadialGradient in the shaderCallback. Set the center and radius properties on RadialGradient to control where the effect originates. This is useful for vignette effects (dark edges, bright center) on images.
Where can I find pre-written Flutter GLSL shaders to use as a starting point?
Shadertoy.com has thousands of GLSL shaders, but they use WebGL conventions — you need to adapt them for Flutter by replacing gl_FragCoord with FlutterFragCoord() and adjusting coordinate systems. The Flutter gallery on GitHub has working FragmentProgram examples, and the flutter_shaders pub.dev package includes ready-to-use shader utilities.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation