Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Use Custom Shaders in FlutterFlow for Visual Effects

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.

What you'll learn

  • Using BackdropFilter for frosted glass and blur effects without code export
  • Applying ShaderMask for gradient and color blend overlays
  • Writing a basic GLSL fragment shader and loading it via FragmentProgram
  • Which shader effects work in web preview vs. native device builds
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner9 min read40-60 minFlutterFlow Pro+ (code export required for GLSL shaders; BackdropFilter works on all plans)March 2026RapidDev Engineering Team
TL;DR

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

1

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.

2

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.

gradient_text_widget.dart
1// Custom Widget: GradientText
2import 'package:flutter/material.dart';
3
4class 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 });
12
13 final String text;
14 final TextStyle style;
15 final Color startColor;
16 final Color endColor;
17
18 @override
19 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.

3

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.

assets/shaders/ripple.frag
1// assets/shaders/ripple.frag
2#include <flutter/runtime_effect.glsl>
3
4uniform float uTime;
5uniform vec2 uCenter;
6uniform sampler2D uTexture;
7
8out vec4 fragColor;
9
10void main() {
11 vec2 fragCoord = FlutterFragCoord().xy;
12 vec2 uv = fragCoord / vec2(400.0, 800.0);
13
14 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);
17
18 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.

4

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.

ripple_shader_widget.dart
1// Custom Widget: RippleShaderWidget
2import 'dart:ui' as ui;
3import 'package:flutter/material.dart';
4import 'package:flutter/scheduler.dart';
5
6class RippleShaderWidget extends StatefulWidget {
7 const RippleShaderWidget({super.key, required this.child});
8 final Widget child;
9
10 @override
11 State<RippleShaderWidget> createState() => _RippleShaderWidgetState();
12}
13
14class _RippleShaderWidgetState extends State<RippleShaderWidget>
15 with SingleTickerProviderStateMixin {
16 ui.FragmentProgram? _program;
17 double _time = 0;
18 late final Ticker _ticker;
19
20 @override
21 void initState() {
22 super.initState();
23 _loadShader();
24 _ticker = createTicker((elapsed) {
25 setState(() => _time = elapsed.inMilliseconds / 1000.0);
26 });
27 _ticker.start();
28 }
29
30 Future<void> _loadShader() async {
31 final program = await ui.FragmentProgram.fromAsset('shaders/ripple.frag');
32 if (mounted) setState(() => _program = program);
33 }
34
35 @override
36 void dispose() {
37 _ticker.dispose();
38 super.dispose();
39 }
40
41 @override
42 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}
54
55class _ShaderPainter extends CustomPainter {
56 _ShaderPainter(this.shader);
57 final ui.FragmentShader shader;
58
59 @override
60 void paint(Canvas canvas, Size size) {
61 canvas.drawRect(Offset.zero & size, Paint()..shader = shader);
62 }
63
64 @override
65 bool shouldRepaint(_ShaderPainter old) => true;
66}

Expected result: The widget renders with an animated ripple distortion effect running at 60fps on physical devices.

5

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

gradient_image_fade_widget.dart
1// FlutterFlow Custom Widget: GradientFadeImage
2// Applies a bottom-to-transparent gradient fade over an image
3// Works on all platforms including web
4// Add as Custom Widget in FlutterFlow Custom Code section
5
6import 'package:flutter/material.dart';
7
8class 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 });
17
18 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 fades
23
24 @override
25 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.

ChatGPT Prompt

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.

FlutterFlow Prompt

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.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.