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

Dotted thought-orb loading indicators for AI & agent UIs. Six hand-tuned animated states, monochrome and theme-aware, drawn with plain Canvas circles.

example/lib/main.dart

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

void main() => runApp(const ExampleApp());

/// Demo app for the flutter_thinking_orbs package.
class ExampleApp extends StatefulWidget {
  /// Creates the demo app.
  const ExampleApp({super.key});

  @override
  State<ExampleApp> createState() => _ExampleAppState();
}

class _ExampleAppState extends State<ExampleApp> {
  Brightness _brightness = Brightness.dark;
  double _size = 96;
  double _speed = 1;
  bool _paused = false;

  @override
  Widget build(BuildContext context) {
    final dark = _brightness == Brightness.dark;
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(brightness: _brightness, useMaterial3: true),
      home: Scaffold(
        backgroundColor:
            dark ? const Color(0xFF101013) : const Color(0xFFF5F5F4),
        appBar: AppBar(
          backgroundColor: Colors.transparent,
          title: const Text('flutter_thinking_orbs'),
          actions: [
            IconButton(
              tooltip: dark ? 'Switch to light' : 'Switch to dark',
              icon: Icon(
                dark ? Icons.light_mode_outlined : Icons.dark_mode_outlined,
              ),
              onPressed: () => setState(
                () => _brightness = dark ? Brightness.light : Brightness.dark,
              ),
            ),
          ],
        ),
        body: Column(
          children: [
            Expanded(
              child: GridView.count(
                padding: const EdgeInsets.all(24),
                crossAxisCount: MediaQuery.sizeOf(context).width > 640 ? 3 : 2,
                mainAxisSpacing: 24,
                crossAxisSpacing: 24,
                children: [
                  for (final state in OrbState.values)
                    _OrbCell(
                      state: state,
                      size: _size,
                      speed: _speed,
                      paused: _paused,
                      dark: dark,
                    ),
                ],
              ),
            ),
            _Controls(
              size: _size,
              speed: _speed,
              paused: _paused,
              onSize: (v) => setState(() => _size = v),
              onSpeed: (v) => setState(() => _speed = v),
              onPaused: (v) => setState(() => _paused = v),
            ),
          ],
        ),
      ),
    );
  }
}

class _OrbCell extends StatelessWidget {
  const _OrbCell({
    required this.state,
    required this.size,
    required this.speed,
    required this.paused,
    required this.dark,
  });

  final OrbState state;
  final double size;
  final double speed;
  final bool paused;
  final bool dark;

  @override
  Widget build(BuildContext context) {
    final ink = dark ? Colors.white70 : Colors.black87;
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Expanded(
          child: Center(
            child: ThinkingOrb(
              state: state,
              size: size,
              speed: speed,
              paused: paused,
            ),
          ),
        ),
        const SizedBox(height: 12),
        Text(
          state.name,
          style: TextStyle(color: ink, fontSize: 13, letterSpacing: 0.2),
        ),
      ],
    );
  }
}

class _Controls extends StatelessWidget {
  const _Controls({
    required this.size,
    required this.speed,
    required this.paused,
    required this.onSize,
    required this.onSpeed,
    required this.onPaused,
  });

  final double size;
  final double speed;
  final bool paused;
  final ValueChanged<double> onSize;
  final ValueChanged<double> onSpeed;
  final ValueChanged<bool> onPaused;

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      top: false,
      child: Padding(
        padding: const EdgeInsets.fromLTRB(24, 0, 24, 16),
        child: Column(
          children: [
            _Slider(
              label: 'size',
              value: size,
              min: 16,
              max: 160,
              display: size.round().toString(),
              onChanged: onSize,
            ),
            _Slider(
              label: 'speed',
              value: speed,
              min: 0.1,
              max: 3,
              display: '${speed.toStringAsFixed(1)}×',
              onChanged: onSpeed,
            ),
            Row(
              children: [
                const SizedBox(width: 4),
                const Text('paused'),
                const Spacer(),
                Switch(value: paused, onChanged: onPaused),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class _Slider extends StatelessWidget {
  const _Slider({
    required this.label,
    required this.value,
    required this.min,
    required this.max,
    required this.display,
    required this.onChanged,
  });

  final String label;
  final double value;
  final double min;
  final double max;
  final String display;
  final ValueChanged<double> onChanged;

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        SizedBox(width: 56, child: Text(label)),
        Expanded(
          child: Slider(value: value, min: min, max: max, onChanged: onChanged),
        ),
        SizedBox(width: 44, child: Text(display, textAlign: TextAlign.end)),
      ],
    );
  }
}
1
likes
160
points
50
downloads

Documentation

API reference

Publisher

verified publisheretornam.dev

Weekly Downloads

Dotted thought-orb loading indicators for AI & agent UIs. Six hand-tuned animated states, monochrome and theme-aware, drawn with plain Canvas circles.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on flutter_thinking_orbs