glow_effects 0.1.0 copy "glow_effects: ^0.1.0" to clipboard
glow_effects: ^0.1.0 copied to clipboard

GPU-native visual effects for Flutter — Fragment Shaders, CustomPainter & Explicit Animations. 10 shader effects, 4 painters, text effects, page transitions & more.

example/lib/main.dart

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:glow_effects/glow_effects.dart';

void main() {
  runApp(const ShaderEffectsExampleApp());
}

class ShaderEffectsExampleApp extends StatelessWidget {
  const ShaderEffectsExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Shader Effects Showcase',
      debugShowCheckedModeBanner: false,
      theme: ThemeData.dark(
        useMaterial3: true,
      ).copyWith(scaffoldBackgroundColor: const Color(0xFF0A0A0A)),
      home: const ShowcaseShell(),
    );
  }
}

// ---------------------------------------------------------------------------
// Shell — bottom navigation with debug overlay toggle
// ---------------------------------------------------------------------------

class ShowcaseShell extends StatefulWidget {
  const ShowcaseShell({super.key});

  @override
  State<ShowcaseShell> createState() => _ShowcaseShellState();
}

class _ShowcaseShellState extends State<ShowcaseShell> {
  int _tabIndex = 0;
  bool _showDebug = false;

  static const _tabs = <Widget>[
    _ShadersTab(),
    _PaintersTab(),
    _TextTab(),
    _TransitionsTab(),
    _ComposerTab(),
  ];

  @override
  Widget build(BuildContext context) {
    Widget body = Scaffold(
      body: IndexedStack(index: _tabIndex, children: _tabs),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _tabIndex,
        onTap: (i) => setState(() => _tabIndex = i),
        type: BottomNavigationBarType.fixed,
        selectedItemColor: Colors.cyanAccent,
        unselectedItemColor: Colors.white38,
        backgroundColor: const Color(0xFF111111),
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.auto_awesome),
            label: 'Shaders',
          ),
          BottomNavigationBarItem(icon: Icon(Icons.brush), label: 'Painters'),
          BottomNavigationBarItem(icon: Icon(Icons.text_fields), label: 'Text'),
          BottomNavigationBarItem(
            icon: Icon(Icons.swap_horiz),
            label: 'Transitions',
          ),
          BottomNavigationBarItem(icon: Icon(Icons.layers), label: 'Composer'),
        ],
      ),
      floatingActionButton: FloatingActionButton.small(
        onPressed: () => setState(() => _showDebug = !_showDebug),
        backgroundColor: _showDebug ? Colors.cyanAccent : Colors.white24,
        child: Icon(
          Icons.bug_report,
          color: _showDebug ? Colors.black : Colors.white,
        ),
      ),
    );

    if (_showDebug) {
      body = GKDebugOverlay(showFps: true, showUniforms: true, child: body);
    }

    return body;
  }
}

// ---------------------------------------------------------------------------
// Shared effect card
// ---------------------------------------------------------------------------

class _EffectCard extends StatelessWidget {
  const _EffectCard({required this.title, required this.onTap, this.subtitle});

  final String title;
  final String? subtitle;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    return Card(
      color: Colors.white10,
      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
      clipBehavior: Clip.antiAlias,
      child: ListTile(
        title: Text(title, style: const TextStyle(color: Colors.white)),
        subtitle: subtitle != null
            ? Text(
                subtitle!,
                style: const TextStyle(color: Colors.white38, fontSize: 12),
              )
            : null,
        trailing: const Icon(
          Icons.arrow_forward_ios,
          size: 14,
          color: Colors.white24,
        ),
        onTap: onTap,
      ),
    );
  }
}

Widget _demoScaffold(String title, Widget body) {
  return Scaffold(
    appBar: AppBar(title: Text(title)),
    body: body,
  );
}

// ---------------------------------------------------------------------------
// Tab 1: Shaders
// ---------------------------------------------------------------------------

class _ShadersTab extends StatelessWidget {
  const _ShadersTab();

  @override
  Widget build(BuildContext context) {
    final effects = <(String, String, Widget)>[
      (
        'Glitch',
        'Block displacement + RGB split + scanlines',
        const _GlitchDemo(),
      ),
      ('Aurora', 'Layered sine waves + HSL cycling', const _AuroraDemo()),
      (
        'Dissolve',
        'Noise-based dissolve with spark edge',
        const _DissolveDemo(),
      ),
      ('Liquid', 'Organic flowing color waves', const _LiquidDemo()),
      (
        'Chromatic Aberration',
        'RGB channel split with radial falloff',
        const _ChromaticDemo(),
      ),
      ('Pixelate', 'Mosaic grid + color quantization', const _PixelateDemo()),
      ('VHS', 'Scanlines + noise + tracking errors', const _VHSDemo()),
      ('Heat Wave', 'Rising sine distortion', const _HeatWaveDemo()),
      ('Neon Glow', 'Bloom + flicker on neon shapes', const _NeonGlowDemo()),
      (
        'Holographic',
        'Rainbow iridescence + fresnel + sparkle',
        const _HolographicDemo(),
      ),
    ];

    return _demoScaffold(
      'Shader Effects',
      ListView.builder(
        padding: const EdgeInsets.symmetric(vertical: 8),
        itemCount: effects.length,
        itemBuilder: (context, i) {
          final (title, subtitle, page) = effects[i];
          return _EffectCard(
            title: title,
            subtitle: subtitle,
            onTap: () => Navigator.of(
              context,
            ).push(GKPageRoute(page: page, type: GKTransitionType.warp)),
          );
        },
      ),
    );
  }
}

class _GlitchDemo extends StatelessWidget {
  const _GlitchDemo();

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'Glitch Effect',
      const SizedBox.expand(
        child: GKWidget(
          effect: GlitchEffect(blockSize: 0.05, rgbOffset: 0.015),
          trigger: GKTrigger.auto,
        ),
      ),
    );
  }
}

class _AuroraDemo extends StatelessWidget {
  const _AuroraDemo();

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'Aurora Effect',
      const SizedBox.expand(
        child: GKWidget(
          effect: AuroraEffect(speed: 1.0, colorShift: 0.0),
          trigger: GKTrigger.auto,
          interactive: true,
        ),
      ),
    );
  }
}

class _DissolveDemo extends StatefulWidget {
  const _DissolveDemo();

  @override
  State<_DissolveDemo> createState() => _DissolveDemoState();
}

class _DissolveDemoState extends State<_DissolveDemo> {
  double _progress = 0.0;

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'Dissolve Effect',
      Column(
        children: [
          Expanded(
            child: GKWidget(
              effect: DissolveEffect(
                progress: _progress,
                noiseScale: 4.0,
                edgeSoftness: 0.1,
              ),
              trigger: GKTrigger.auto,
              child: Center(
                child: Container(
                  width: 200,
                  height: 200,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(24),
                    gradient: const LinearGradient(
                      colors: [Colors.deepPurple, Colors.cyanAccent],
                    ),
                  ),
                  child: const Center(
                    child: Icon(
                      Icons.auto_awesome,
                      size: 64,
                      color: Colors.white,
                    ),
                  ),
                ),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(24),
            child: Column(
              children: [
                Text(
                  'Progress: ${_progress.toStringAsFixed(2)}',
                  style: const TextStyle(color: Colors.white70),
                ),
                Slider(
                  value: _progress,
                  onChanged: (v) => setState(() => _progress = v),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class _LiquidDemo extends StatelessWidget {
  const _LiquidDemo();

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'Liquid Effect',
      const SizedBox.expand(
        child: GKWidget(
          effect: LiquidEffect(speed: 1.0, viscosity: 0.5),
          trigger: GKTrigger.auto,
        ),
      ),
    );
  }
}

class _ChromaticDemo extends StatelessWidget {
  const _ChromaticDemo();

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'Chromatic Aberration',
      const SizedBox.expand(
        child: GKWidget(
          effect: ChromaticAberrationEffect(offset: 0.02, angle: 0.0),
          trigger: GKTrigger.auto,
        ),
      ),
    );
  }
}

class _PixelateDemo extends StatelessWidget {
  const _PixelateDemo();

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'Pixelate Effect',
      const SizedBox.expand(
        child: GKWidget(
          effect: PixelateEffect(pixelSize: 10.0, animate: true),
          trigger: GKTrigger.auto,
        ),
      ),
    );
  }
}

class _VHSDemo extends StatelessWidget {
  const _VHSDemo();

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'VHS Effect',
      const SizedBox.expand(
        child: GKWidget(
          effect: VHSEffect(noiseAmount: 0.12, trackingError: 0.06),
          trigger: GKTrigger.auto,
        ),
      ),
    );
  }
}

class _HeatWaveDemo extends StatelessWidget {
  const _HeatWaveDemo();

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'Heat Wave Effect',
      const SizedBox.expand(
        child: GKWidget(
          effect: HeatWaveEffect(frequency: 8.0, amplitude: 0.015),
          trigger: GKTrigger.auto,
        ),
      ),
    );
  }
}

class _NeonGlowDemo extends StatelessWidget {
  const _NeonGlowDemo();

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'Neon Glow Effect',
      const SizedBox.expand(
        child: GKWidget(
          effect: NeonGlowEffect(
            glowRadius: 0.05,
            flickerSpeed: 3.0,
            glowColor: Color(0xFF00FFFF),
          ),
          trigger: GKTrigger.auto,
        ),
      ),
    );
  }
}

class _HolographicDemo extends StatelessWidget {
  const _HolographicDemo();

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'Holographic Effect',
      const SizedBox.expand(
        child: GKWidget(
          effect: HolographicEffect(speed: 1.0, fresnelPower: 2.0),
          trigger: GKTrigger.auto,
          interactive: true,
        ),
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// Tab 2: Painters
// ---------------------------------------------------------------------------

class _PaintersTab extends StatelessWidget {
  const _PaintersTab();

  @override
  Widget build(BuildContext context) {
    final painters = <(String, String, Widget)>[
      (
        'Magnetic Particles',
        'Spring-physics particles attracted to pointer',
        const _ParticlesDemo(),
      ),
      ('Morph Shape', 'Circle-to-star path interpolation', const _MorphDemo()),
      (
        'Constellation',
        'Connected star network with pointer interaction',
        const _ConstellationDemo(),
      ),
      (
        'Lightning',
        'Midpoint displacement bolt with branches',
        const _LightningDemo(),
      ),
    ];

    return _demoScaffold(
      'CustomPainter Effects',
      ListView.builder(
        padding: const EdgeInsets.symmetric(vertical: 8),
        itemCount: painters.length,
        itemBuilder: (context, i) {
          final (title, subtitle, page) = painters[i];
          return _EffectCard(
            title: title,
            subtitle: subtitle,
            onTap: () => Navigator.of(
              context,
            ).push(GKPageRoute(page: page, type: GKTransitionType.ripple)),
          );
        },
      ),
    );
  }
}

class _ParticlesDemo extends StatefulWidget {
  const _ParticlesDemo();

  @override
  State<_ParticlesDemo> createState() => _ParticlesDemoState();
}

class _ParticlesDemoState extends State<_ParticlesDemo>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;
  Offset _pointer = Offset.zero;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 4),
    )..repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'Magnetic Particles',
      LayoutBuilder(
        builder: (context, constraints) {
          final size = Size(constraints.maxWidth, constraints.maxHeight);
          return MouseRegion(
            onHover: (e) => setState(() => _pointer = e.localPosition),
            child: GestureDetector(
              onPanUpdate: (d) => setState(() => _pointer = d.localPosition),
              child: AnimatedBuilder(
                animation: _controller,
                builder: (context, _) {
                  return CustomPaint(
                    size: size,
                    painter: MagneticParticlesPainter(
                      particleCount: 80,
                      colors: const [
                        Colors.cyanAccent,
                        Colors.purpleAccent,
                        Colors.tealAccent,
                        Colors.pinkAccent,
                      ],
                      magnetStrength: 150.0,
                      animationValue: _controller.value,
                      pointerPosition: _pointer,
                      size: size,
                    ),
                  );
                },
              ),
            ),
          );
        },
      ),
    );
  }
}

class _MorphDemo extends StatefulWidget {
  const _MorphDemo();

  @override
  State<_MorphDemo> createState() => _MorphDemoState();
}

class _MorphDemoState extends State<_MorphDemo>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2),
    )..repeat(reverse: true);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  Path _circlePath(Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final radius = size.shortestSide * 0.35;
    return Path()..addOval(Rect.fromCircle(center: center, radius: radius));
  }

  Path _starPath(Size size) {
    final cx = size.width / 2;
    final cy = size.height / 2;
    final outerR = size.shortestSide * 0.35;
    final innerR = outerR * 0.4;
    const points = 5;
    final path = Path();
    for (var i = 0; i < points * 2; i++) {
      final angle = (i * pi / points) - pi / 2;
      final r = i.isEven ? outerR : innerR;
      final x = cx + r * cos(angle);
      final y = cy + r * sin(angle);
      if (i == 0) {
        path.moveTo(x, y);
      } else {
        path.lineTo(x, y);
      }
    }
    path.close();
    return path;
  }

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'Morph Shape',
      LayoutBuilder(
        builder: (context, constraints) {
          final size = Size(constraints.maxWidth, constraints.maxHeight);
          return AnimatedBuilder(
            animation: _controller,
            builder: (context, _) {
              return CustomPaint(
                size: size,
                painter: MorphShapePainter(
                  fromPath: _circlePath(size),
                  toPath: _starPath(size),
                  progress: _controller.value,
                  color: Colors.cyanAccent,
                  strokeWidth: 3.0,
                ),
              );
            },
          );
        },
      ),
    );
  }
}

class _ConstellationDemo extends StatefulWidget {
  const _ConstellationDemo();

  @override
  State<_ConstellationDemo> createState() => _ConstellationDemoState();
}

class _ConstellationDemoState extends State<_ConstellationDemo>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;
  Offset _pointer = Offset.zero;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 8),
    )..repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'Constellation',
      LayoutBuilder(
        builder: (context, constraints) {
          final size = Size(constraints.maxWidth, constraints.maxHeight);
          return MouseRegion(
            onHover: (e) => setState(() => _pointer = e.localPosition),
            child: GestureDetector(
              onPanUpdate: (d) => setState(() => _pointer = d.localPosition),
              child: AnimatedBuilder(
                animation: _controller,
                builder: (context, _) {
                  return CustomPaint(
                    size: size,
                    painter: ConstellationPainter(
                      starCount: 60,
                      connectionRadius: 120.0,
                      starColor: Colors.white,
                      lineColor: Colors.white24,
                      animationValue: _controller.value,
                      pointerPosition: _pointer,
                      size: size,
                    ),
                  );
                },
              ),
            ),
          );
        },
      ),
    );
  }
}

class _LightningDemo extends StatefulWidget {
  const _LightningDemo();

  @override
  State<_LightningDemo> createState() => _LightningDemoState();
}

class _LightningDemoState extends State<_LightningDemo>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2),
    )..repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      'Lightning',
      LayoutBuilder(
        builder: (context, constraints) {
          final size = Size(constraints.maxWidth, constraints.maxHeight);
          return AnimatedBuilder(
            animation: _controller,
            builder: (context, _) {
              return CustomPaint(
                size: size,
                painter: LightningPainter(
                  start: Offset(size.width / 2, 40),
                  end: Offset(size.width / 2, size.height - 40),
                  animationValue: _controller.value,
                  color: const Color(0xFFE0E0FF),
                  branches: 4,
                  roughness: 0.6,
                ),
              );
            },
          );
        },
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// Tab 3: Text Effects
// ---------------------------------------------------------------------------

class _TextTab extends StatelessWidget {
  const _TextTab();

  @override
  Widget build(BuildContext context) {
    final effects = <(String, GKTextEffectType)>[
      ('Typewriter Glow', GKTextEffectType.typewriterGlow),
      ('Neon Flicker', GKTextEffectType.neonFlicker),
      ('Glitch Reveal', GKTextEffectType.glitchReveal),
      ('Dissolve In', GKTextEffectType.dissolveIn),
    ];

    return _demoScaffold(
      'Text Effects',
      ListView.builder(
        padding: const EdgeInsets.symmetric(vertical: 8),
        itemCount: effects.length,
        itemBuilder: (context, i) {
          final (title, type) = effects[i];
          return _EffectCard(
            title: title,
            onTap: () => Navigator.of(context).push(
              GKPageRoute(
                page: _TextDemo(title: title, type: type),
                type: GKTransitionType.glitch,
              ),
            ),
          );
        },
      ),
    );
  }
}

class _TextDemo extends StatefulWidget {
  const _TextDemo({required this.title, required this.type});
  final String title;
  final GKTextEffectType type;

  @override
  State<_TextDemo> createState() => _TextDemoState();
}

class _TextDemoState extends State<_TextDemo> {
  int _key = 0;

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      widget.title,
      Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            GKTextEffect(
              key: ValueKey(_key),
              text: 'Shader Effects',
              effect: widget.type,
              style: const TextStyle(
                fontSize: 28,
                fontWeight: FontWeight.bold,
                color: Colors.cyanAccent,
              ),
              duration: const Duration(milliseconds: 2500),
            ),
            const SizedBox(height: 32),
            TextButton.icon(
              onPressed: () => setState(() => _key++),
              icon: const Icon(Icons.replay),
              label: const Text('Replay'),
            ),
          ],
        ),
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// Tab 4: Transitions
// ---------------------------------------------------------------------------

class _TransitionsTab extends StatelessWidget {
  const _TransitionsTab();

  @override
  Widget build(BuildContext context) {
    final types = GKTransitionType.values;

    return _demoScaffold(
      'Page Transitions',
      ListView.builder(
        padding: const EdgeInsets.symmetric(vertical: 8),
        itemCount: types.length,
        itemBuilder: (context, i) {
          final type = types[i];
          final name = type.name[0].toUpperCase() + type.name.substring(1);
          return _EffectCard(
            title: '$name Transition',
            onTap: () => Navigator.of(context).push(
              GKPageRoute(
                page: _TransitionTarget(typeName: name),
                type: type,
              ),
            ),
          );
        },
      ),
    );
  }
}

class _TransitionTarget extends StatelessWidget {
  const _TransitionTarget({required this.typeName});
  final String typeName;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('$typeName Transition')),
      body: Center(
        child: Text(
          typeName.toUpperCase(),
          style: const TextStyle(
            fontSize: 32,
            fontWeight: FontWeight.bold,
            color: Colors.white54,
          ),
        ),
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// Tab 5: Composer / Presets
// ---------------------------------------------------------------------------

class _ComposerTab extends StatelessWidget {
  const _ComposerTab();

  @override
  Widget build(BuildContext context) {
    final presets = <(String, String, GKPreset)>[
      ('Cyberpunk', 'Glitch + Chromatic + Neon Glow', GKPreset.cyberpunk),
      ('Dreamy', 'Aurora + Dissolve', GKPreset.dreamy),
      ('Retro', 'VHS + Pixelate', GKPreset.retro),
      ('Minimal', 'Subtle Neon Glow', GKPreset.minimal),
    ];

    return _demoScaffold(
      'Effect Composer',
      ListView(
        padding: const EdgeInsets.symmetric(vertical: 8),
        children: [
          const Padding(
            padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: Text(
              'Presets',
              style: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.bold,
                color: Colors.white54,
              ),
            ),
          ),
          ...presets.map((p) {
            final (title, subtitle, preset) = p;
            return _EffectCard(
              title: title,
              subtitle: subtitle,
              onTap: () => Navigator.of(context).push(
                GKPageRoute(
                  page: _PresetDemo(title: title, preset: preset),
                  type: GKTransitionType.warp,
                ),
              ),
            );
          }),
          const Padding(
            padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: Text(
              'Custom Compose',
              style: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.bold,
                color: Colors.white54,
              ),
            ),
          ),
          _EffectCard(
            title: 'Liquid + Neon Glow (Screen)',
            subtitle: 'Two effects blended with screen mode',
            onTap: () => Navigator.of(context).push(
              GKPageRoute(
                page: _demoScaffold(
                  'Liquid + Neon Glow',
                  const SizedBox.expand(
                    child: GKWidget(
                      effect: GKEffectComposer(
                        effects: [
                          LiquidEffect(speed: 0.8, viscosity: 0.6),
                          NeonGlowEffect(
                            glowRadius: 0.04,
                            glowColor: Color(0xFFFF00FF),
                          ),
                        ],
                        blend: GKBlendMode.screen,
                      ),
                      trigger: GKTrigger.auto,
                    ),
                  ),
                ),
                type: GKTransitionType.ripple,
              ),
            ),
          ),
          _EffectCard(
            title: 'Aurora + Heat Wave (Overlay)',
            subtitle: 'Nature effects blended with overlay mode',
            onTap: () => Navigator.of(context).push(
              GKPageRoute(
                page: _demoScaffold(
                  'Aurora + Heat Wave',
                  const SizedBox.expand(
                    child: GKWidget(
                      effect: GKEffectComposer(
                        effects: [
                          AuroraEffect(speed: 0.6, colorShift: 0.1),
                          HeatWaveEffect(frequency: 6.0, amplitude: 0.012),
                        ],
                        blend: GKBlendMode.overlay,
                      ),
                      trigger: GKTrigger.auto,
                    ),
                  ),
                ),
                type: GKTransitionType.ripple,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class _PresetDemo extends StatelessWidget {
  const _PresetDemo({required this.title, required this.preset});
  final String title;
  final GKPreset preset;

  @override
  Widget build(BuildContext context) {
    return _demoScaffold(
      title,
      SizedBox.expand(
        child: GKWidget(
          effect: GKAnimationPresets.preset(preset),
          trigger: GKTrigger.auto,
        ),
      ),
    );
  }
}
1
likes
160
points
111
downloads

Documentation

API reference

Publisher

verified publisheraibekk.dev

Weekly Downloads

GPU-native visual effects for Flutter — Fragment Shaders, CustomPainter & Explicit Animations. 10 shader effects, 4 painters, text effects, page transitions & more.

Repository (GitHub)
View/report issues

Topics

#shader #animation #effects #visual #gpu

License

MIT (license)

Dependencies

flutter

More

Packages that depend on glow_effects