Open Source

Flutter package

flutter_shaders_ui

GPU-accelerated GLSL shader effects for Flutter UI — ten drop-in widgets, zero dependencies.

v1.1.223.2k / month40 likesMIT10 effectsFlutter SDK only

API reference

Every public widget and core class with constructor parameters, types and defaults: the effects, GlowOrb, ShaderEffectWidget, ShaderPainter and ShaderCache.

source: README.md

API

Library exports

A single import — package:flutter_shaders_ui/flutter_shaders_ui.dart — brings in the whole public surface: three core building blocks, one callback typedef, and ten drop-in effect widgets. Nothing else is exported; the shaders themselves ship as bundled .frag assets.

SymbolKindSummary
ShaderEffectWidgetWidgetBase widget — loads a .frag asset, drives the time animation, sets standard uniforms.
ShaderUniformSetterTypedefThe per-frame callback that sets custom shader uniforms.
ShaderCacheClass (static)Global cache of compiled FragmentProgram instances, keyed by asset path.
ShaderPainterCustomPainterReusable painter that draws a rect filled with a FragmentShader.
AuroraEffectWidgetAnimated aurora / northern-lights overlay.
FireEffectWidgetFlickering flames rising from the bottom.
GlassEffectWidgetFrosted-glass / glassmorphism overlay.
GlowOrbWidgetPositionable glowing orb — static, bouncing or draggable.
PulseEffectWidgetBreathing radial glow with expanding pulse rings.
RippleEffectWidgetTap-triggered expanding ripple overlay.
ShimmerEffectWidgetSweeping shimmer highlight for placeholders.
SnowEffectWidgetFalling snow particles with parallax depth.
WaterEffectWidgetAnimated water surface with caustics and foam.
WaveBackgroundWidgetAnimated wave gradient background.

API

Effect widget signatures

Every effect is a plain widget you drop into your tree. Their constructor signatures are listed below for quick reference. For the full parameter tables — ranges, defaults and per-parameter notes — plus a working example for each, see the Effects reference.

WaveBackgrounddart
const WaveBackground({
  super.key,
  this.child,
  this.color1 = const Color(0xFF1A237E),
  this.color2 = const Color(0xFF00BCD4),
  this.amplitude = 0.3,
  this.frequency = 2.0,
  this.speed = 1.0,
  this.enabled = true,
})
WaterEffectdart
const WaterEffect({
  super.key,
  this.child,
  this.color1 = const Color(0xFF26C6DA),
  this.color2 = const Color(0xFF0D47A1),
  this.speed = 1.0,
  this.depth = 0.5,
  this.waveIntensity = 0.5,
  this.causticIntensity = 0.6,
  this.foamAmount = 0.0,
  this.enabled = true,
})
AuroraEffectdart
const AuroraEffect({
  super.key,
  this.child,
  this.color1 = const Color(0xFF00E676),
  this.color2 = const Color(0xFFAA00FF),
  this.intensity = 0.6,
  this.speed = 1.0,
  this.enabled = true,
})
FireEffectdart
const FireEffect({
  super.key,
  this.child,
  this.intensity = 0.6,
  this.speed = 1.0,
  this.color1 = const Color(0xFFFFEB3B),
  this.color2 = const Color(0xFFFF5722),
  this.enabled = true,
})
GlassEffectdart
const GlassEffect({
  super.key,
  this.child,
  this.blurAmount = 0.5,
  this.frost = 0.4,
  this.opacity = 0.3,
  this.tint = const Color(0xFFFFFFFF),
  this.enabled = true,
})
PulseEffectdart
const PulseEffect({
  super.key,
  this.child,
  this.color = const Color(0xFF2196F3),
  this.speed = 1.0,
  this.intensity = 0.5,
  this.enabled = true,
})
ShimmerEffectdart
const ShimmerEffect({
  super.key,
  this.child,
  this.color = const Color(0x40FFFFFF),
  this.angle = 0.5,
  this.speed = 1.0,
  this.width = 0.3,
  this.enabled = true,
})
SnowEffectdart
const SnowEffect({
  super.key,
  this.child,
  this.density = 0.5,
  this.speed = 1.0,
  this.size = 0.5,
  this.enabled = true,
})
RippleEffectdart
const RippleEffect({
  super.key,
  required this.child,
  this.color = Colors.white,
  this.duration = _defaultRippleDuration,
  this.intensity = _defaultRippleIntensity,
  this.onTap,
})

Resolved defaults: duration = Duration(milliseconds: 800), intensity = 1.0. RippleEffect is the only effect without an enabled flag — the shader runs only while a tap animation is in flight.

GlowOrb (three constructors)dart
const GlowOrb({
  super.key,
  this.position = const Offset(0.5, 0.5),
  this.color = Colors.cyan,
  this.radius = _defaultRadius,
  this.glowIntensity = _defaultGlowIntensity,
  this.pulseSpeed = _defaultPulseSpeed,
  this.enabled = true,
  this.child,
})

const GlowOrb.bouncing({
  super.key,
  this.color = Colors.purple,
  this.radius = _defaultRadius,
  this.glowIntensity = _defaultGlowIntensity,
  this.pulseSpeed = _defaultPulseSpeed,
  this.enabled = true,
  this.child,
  double speed = _defaultBounceSpeed,
})

const GlowOrb.draggable({
  super.key,
  this.position = const Offset(0.5, 0.5),
  this.color = Colors.orange,
  this.radius = _defaultRadius,
  this.glowIntensity = _defaultGlowIntensity,
  this.pulseSpeed = _defaultPulseSpeed,
  this.enabled = true,
  this.child,
})

Resolved defaults: _defaultRadius = 0.15, _defaultGlowIntensity = 1.0, _defaultPulseSpeed = 2.0, _defaultBounceSpeed = 0.3. The default color differs per mode: Colors.cyan (static), Colors.purple (bouncing), Colors.orange (draggable).

Core API

ShaderEffectWidget

The base widget behind every effect. It loads a .frag asset through ShaderCache, runs a Ticker for the time animation, wraps the paint in a RepaintBoundary, and feeds the shader its standard uniforms. Build your own effects on top of it — see Custom shaders.

dart
const ShaderEffectWidget({
  super.key,
  required this.assetPath,
  this.child,
  this.uniformSetter,
  this.enabled = true,
  this.showAsOverlay = false,
  this.timeScale = 1.0,
})
ParameterTypeReq.DefaultDescription
assetPathStringYesPath to the .frag shader asset.
childWidget?NonullOptional child. Rendered behind or under the shader effect.
uniformSetterShaderUniformSetter?NonullCallback to set custom uniforms beyond the standard ones.
enabledboolNotrueWhether the shader is active. When false, only child renders.
showAsOverlayboolNofalseIf true, shader renders on top of child; if false (default), behind it.
timeScaledoubleNo1.0Multiplier applied to the elapsed time fed into the uTime uniform. 0.5 = half speed, 0.0 freezes, negative runs in reverse.

Standard uniforms are set automatically at indices 0-2. Anything your uniformSetter adds starts at index 3.

IndexGLSL uniformDescription
0-1vec2 uResolutionWidget width & height, in logical pixels.
2float uTimeElapsed seconds.
Minimal usagedart
ShaderEffectWidget(
  assetPath: 'packages/flutter_shaders_ui/shaders/snow.frag',
  child: Text('Hello'),
)

Core API

ShaderCache

A global, static cache for compiled ui.FragmentProgram instances, keyed by asset path — this is what makes "compiled once" true across your whole app. It has a private constructor (ShaderCache._()), so you never instantiate it; you call its static methods. Concurrent loads of the same path are deduplicated: a second load that arrives mid-compile awaits the same in-flight future rather than compiling again. It is thread-safe for single-isolate Flutter usage.

dart
static Future<ui.FragmentProgram> load(String assetPath)
static void evict(String assetPath)
static void clearAll()
MethodReturnsDescription
load(String assetPath)Future<ui.FragmentProgram>Loads a program from the asset path, using the cache. If already loaded, returns the cached instance. If currently loading, awaits the same future (deduplication).
evict(String assetPath)voidEvicts a specific shader from the cache.
clearAll()voidClears all cached (and pending) shaders.
Loading a programdart
final program = await ShaderCache.load('shaders/snow.frag');
final shader = program.fragmentShader();

Core API

ShaderPainter

A bare CustomPainter that fills its canvas rect with a ui.FragmentShader. It does no loading and no animation of its own — the contract is that you set the shader's uniforms before it paints. Pass a Listenable to repaint (for example an AnimationController or a ValueNotifier) to drive repaints; shouldRepaint always returns true. Reach for it when you want a shader on a canvas without the full ShaderEffectWidget lifecycle.

dart
ShaderPainter({
  required this.shader,
  super.repaint,
})
ParameterTypeReq.DefaultDescription
shaderui.FragmentShaderYesThe fragment shader to render. Its uniforms must already be set.
repaintListenable?NonullInherited from CustomPainter via super.repaint. When provided, the painter repaints on each tick.

Types

Support types

The package exports one support type, the ShaderUniformSetter typedef used by ShaderEffectWidget.uniformSetter. There are no public enums.

dart
typedef ShaderUniformSetter = int Function(
  ui.FragmentShader shader,
  Size size,
  double time,
  int index,
);

The callback runs every frame. It receives the live shader, the current widget size (logical pixels), the elapsed time in seconds, and the starting uniform index (which is 3, right after the standard uniforms). Set your floats with shader.setFloat(...) starting at that index, then return the next available index so the framework knows where your uniforms ended. Colors are passed as three separate floats — color.r, color.g, color.b.

Behavior

Errors & fallback

Every effect degrades to its child, never to a crash. Three cases are worth knowing.

  • Disabled (enabled: false). ShaderEffectWidget.build returns child ?? const SizedBox.shrink() and the animation Ticker is stopped, so there is zero GPU cost. Every effect widget forwards its own enabled flag down to this guard — wire it to a reduced-motion setting for accessibility.
  • While loading. Until the FragmentProgram finishes loading the widget renders only its child (the same fallback), and the Ticker starts only once the program has loaded and enabled is true. A missing or invalid .frag asset leaves the program null, so the effect simply never appears and your child keeps rendering — the layout is never torn down.
  • RippleEffect idle cost. It has no enabled parameter; its internal shader is active only while a tap animation runs and switches off when the animation completes, so between taps it too renders only the child.

Zero cost when disabled

The disabled path is the intended way to pause effects — off-screen, on low-end devices, or under reduced motion. A disabled widget draws nothing on the GPU and adds no shader work to the frame.

Let's make something together.

If you have any questions about a new project or other inquiries, feel free to contact us. We will get back to you as soon as possible.

Codigee
We are using cookies. Learn more