From 1b8d56286848b07f71db86891632cd11f2bfa439 Mon Sep 17 00:00:00 2001 From: Richard Brown Date: Sun, 12 Apr 2026 21:45:59 +0100 Subject: [PATCH 1/2] deps: add lottie and particles_flutter for animated intro backgrounds Co-Authored-By: Claude Sonnet 4.6 --- pubspec.lock | 32 ++++++++++++++++++++++++++++++++ pubspec.yaml | 2 ++ 2 files changed, 34 insertions(+) diff --git a/pubspec.lock b/pubspec.lock index 7a42eb6..013abcb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,6 +25,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.13.2" + archive: + dependency: transitive + description: + name: archive + sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff + url: "https://pub.dev" + source: hosted + version: "4.0.9" args: dependency: transitive description: @@ -544,6 +552,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + lottie: + dependency: "direct main" + description: + name: lottie + sha256: c5fa04a80a620066c15cf19cc44773e19e9b38e989ff23ea32e5903ef1015950 + url: "https://pub.dev" + source: hosted + version: "3.3.1" matcher: dependency: transitive description: @@ -592,6 +608,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + particles_flutter: + dependency: "direct main" + description: + name: particles_flutter + sha256: "74057830f0526902cc36325b5feefbbeda88b5f8f9958cf8f24ec98eeeab36c2" + url: "https://pub.dev" + source: hosted + version: "2.0.2" path: dependency: transitive description: @@ -688,6 +712,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + posix: + dependency: transitive + description: + name: posix + sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" + url: "https://pub.dev" + source: hosted + version: "6.5.0" provider: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5eb20da..ffc0b8a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -42,6 +42,8 @@ dependencies: firebase_app_check: ^0.4.2 confetti: ^0.8.0 flutter_staggered_animations: ^1.1.1 + lottie: ^3.1.0 + particles_flutter: ^2.0.2 dev_dependencies: flutter_test: sdk: flutter From f04cc8106c13da232b577d7f0ea565cb2712382a Mon Sep 17 00:00:00 2001 From: Richard Brown Date: Sun, 12 Apr 2026 22:15:14 +0100 Subject: [PATCH 2/2] feat: wire up particles_flutter as animated background in intro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds 25 slow-drifting circular particles (radius 1–4px, white at ~10–22% opacity) that float across the intro gradient using BoundType.WrapAround. Particles are generated once in initState and reused across all steps. Lottie is not yet implemented — a .json asset is required first. Co-Authored-By: Claude Sonnet 4.6 --- lib/intro.dart | 65 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/lib/intro.dart b/lib/intro.dart index c9b109f..d19b38e 100644 --- a/lib/intro.dart +++ b/lib/intro.dart @@ -1,6 +1,9 @@ import 'package:animated_text_kit/animated_text_kit.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'dart:math' as math; + +import 'package:particles_flutter/engine.dart'; import 'package:postbox_game/james_messages.dart'; import 'package:postbox_game/postman_james_svg.dart'; import 'package:postbox_game/theme.dart'; @@ -28,6 +31,7 @@ class _IntroState extends State with TickerProviderStateMixin { late AnimationController _jamesWalkController; late Animation _jamesSlide; + late final List _particles; @override void initState() { @@ -39,6 +43,23 @@ class _IntroState extends State with TickerProviderStateMixin { _jamesSlide = Tween(begin: -1.0, end: 0.0).animate( CurvedAnimation(parent: _jamesWalkController, curve: Curves.easeOut), ); + _particles = _buildParticles(); + } + + static List _buildParticles() { + final rng = math.Random(); + return List.generate(25, (_) { + final speed = 0.3 + rng.nextDouble() * 0.7; + final angle = rng.nextDouble() * 2 * math.pi; + return CircularParticle( + radius: 1.0 + rng.nextDouble() * 3.0, + color: Colors.white.withValues(alpha: 0.1 + rng.nextDouble() * 0.12), + velocity: Offset( + math.cos(angle) * speed * 30, + math.sin(angle) * speed * 30, + ), + ); + }); } @override @@ -74,23 +95,37 @@ class _IntroState extends State with TickerProviderStateMixin { colors: [royalNavy, Color(0xFF3D0C13)], ), ), - child: SafeArea( - child: Column( - children: [ - Expanded(child: _buildStep()), - Padding( - padding: const EdgeInsets.all(AppSpacing.lg), - child: SizedBox( - width: double.infinity, - child: FilledButton( - onPressed: _advance, - child: - Text(_step == _totalSteps - 1 ? 'Get started' : 'Next'), + child: Stack( + children: [ + // Subtle floating particles behind all intro content. + Positioned.fill( + child: Particles( + particles: _particles, + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + boundType: BoundType.WrapAround, + connectDots: false, + ), + ), + SafeArea( + child: Column( + children: [ + Expanded(child: _buildStep()), + Padding( + padding: const EdgeInsets.all(AppSpacing.lg), + child: SizedBox( + width: double.infinity, + child: FilledButton( + onPressed: _advance, + child: Text( + _step == _totalSteps - 1 ? 'Get started' : 'Next'), + ), + ), ), - ), + ], ), - ], - ), + ), + ], ), ), );