flame_gallery 0.1.0
flame_gallery: ^0.1.0 copied to clipboard
Drop-in, brandable 2D mini games (slice, endless runner, match-3, rhythm) for any Flutter app, opened with one FlameGallery.show call.
Flame Gallery #
Drop-in, brandable 2D mini games for any Flutter app, built on Flame. One call opens a full screen game; you get the score back.
final result = await FlameGallery.show(context, game: const FruitSlice());
Play it in your browser · Website · GitHub
| Fruit Slice | Ruins Runner | Sweet Swap | Note Rush |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
| Swipe to slice, avoid bombs | 3 lanes: swipe, jump, slide | Match three or more | Tap notes on the beat |
Why #
- One dependency, one call.
FlameGallery.showpushes a full screen route with start, pause and game over menus, and completes with aGameResult. - Brandable without forking. Colors (
ColorScheme), font, logo, every text, sprites and rules are config. No colors given → the game follows your app theme. - Campaign ready. Timers, lives, move limits, target scores, seeded boards ("daily challenge") and a result with stats you can turn into coupons or points.
- Light on your app. The libraries depend only on
flutterandflame. No state management or codegen packages are forced on you. - Testable. Stable
Semanticsidentifiers on every menu button and HUD value (GalleryKeys), so Maestro / Patrol / integration tests can drive the games.
Install #
flutter pub add flame_gallery
Each game is also its own package (flame_gallery_slice, flame_gallery_runner, flame_gallery_match, flame_gallery_rhythm) if you only want one.
Usage #
import 'package:flame_gallery/flame_gallery.dart';
final result = await FlameGallery.show(
context,
game: FruitSlice(
config: const SliceConfig(
timeLimit: Duration(seconds: 30),
bomb: null, // no bombs in this campaign
),
theme: GameTheme(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF00897B),
brightness: Brightness.dark,
),
logo: const AssetImage('assets/brand_logo.png'),
),
strings: FruitSlice.stringsTr.copyWith(
title: 'Summer Campaign',
instructions: 'Slice as many fruits as you can in 30 seconds!',
),
),
onEvent: (event) => analytics.log('$event'),
);
if (result case GameResult(isCompleted: true, :final score) when score >= 50) {
grantCoupon();
}
The games #
| Game | Class | Config highlights |
|---|---|---|
| Fruit Slice | FruitSlice |
timeLimit, lives, items (your own sprites, points, juice color), bomb, bombChance, difficulty, background |
| Ruins Runner | EndlessRunner |
timeLimit, lives, coinValue, difficulty, sprites, background |
| Sweet Swap | SweetSwap |
rows, columns, pieces, moveLimit, timeLimit, targetScore, seed |
| Note Rush | NoteRush |
song (beat map), difficulty, missLimit, plus a pluggable RhythmAudio so you play music with your own audio stack |
Every game ships English and Turkish texts (stringsEn, stringsTr); override any of them with copyWith.
Configs are immutable. copyWith takes a ValueGetter for nullable fields, so they can be cleared as well as changed:
const base = SliceConfig(lives: 3);
final campaign = base.copyWith(timeLimit: () => const Duration(seconds: 30), bomb: () => null);
Results and events #
GameResult(
gameId: 'fruit_slice',
score: 42,
reason: GameEndReason.completed, // or quit
playTime: Duration(seconds: 30),
stats: {'sliced': 40, 'maxCombo': 4, 'endedBy': 'timeUp'},
);
Read stats through the const keys instead of string literals:
final sliced = result.stats[SliceStatKeys.sliced];
final endedBy = result.stats[GameStatKeys.endedBy]; // 'timeUp', 'bomb', 'quit'...
Each game exports its own keys: SliceStatKeys, RunnerStatKeys, MatchStatKeys, RhythmStatKeys.
onEvent receives GameStarted, GameScoreChanged, GamePaused, GameResumed and GameFinished. GameResult.toJson() gives a flat map for analytics or a platform channel.
Your own assets #
Use GameAsset('assets/my_fruit.png') for files in your app bundle:
FruitSlice(
config: SliceConfig(
items: const [
SliceItem(sprite: GameAsset('assets/products/can.png'), juiceColor: Color(0xFFE53935), points: 2),
SliceItem.orange,
],
),
);
Branding: background, dialogs, HUD #
FlameGallery.show(
context,
game: FruitSlice(
theme: GameTheme(
// Color, gradient or image behind every game's playfield.
background: const GameBackground.gradient(
LinearGradient(colors: [Color(0xFF004D40), Color(0xFF00897B)]),
),
// Full control over buttons, cards and text in the menus.
themeData: myAppTheme,
),
),
// Replace any built-in overlay. `ui` gives strings, score and actions.
overlays: GameOverlayBuilders(
start: (context, ui) => MyBrandDialog(title: ui.strings.title, onStart: ui.start),
gameOver: (context, ui) => MyResultSheet(
score: ui.result()?.score ?? 0,
onAgain: ui.start,
onClose: ui.close,
),
),
);
Animated sprites #
Anything that was a single image can be a horizontal sprite strip:
RunnerSprites(
runnerAnimation: GameAnimation(
GameAsset('assets/hero_run.png'),
frames: 6,
stepTime: 0.08,
),
coinAnimation: GameAnimation(GameAsset('assets/coin_spin.png'), frames: 8),
)
Sound effects #
The library plays nothing itself. Pass a GameSounds and map cues to your audio package:
FlameGallery.show(
context,
game: EndlessRunner(),
sounds: CallbackSounds((cue) => switch (cue) {
GameSoundCue.coin => player.play('coin.mp3'),
GameSoundCue.hit => player.play('crash.mp3'),
_ => null,
}),
);
Cues: start, scoreUp, penalty, gameOver (every game); slice, bomb (Fruit Slice); jump, coin, hit (Ruins Runner); swap, match (Sweet Swap); noteHit, noteMiss (Note Rush).
Difficulty #
Presets stay (SliceDifficulty.hard), and you can tune any number:
SliceConfig(difficulty: SliceDifficulty.normal.copyWith(maxWaveSize: 6, speedFactor: 1.3))
RunnerConfig(difficulty: RunnerDifficulty.hard.copyWith(maxSpeed: 1.8))
RhythmConfig(difficulty: RhythmDifficulty(approachSeconds: 1.1))
System UI #
Games run in immersive mode (system bars hidden) and restore SystemUiMode.edgeToEdge on close. Pass immersive: false to FlameGallery.show if your app manages system UI itself.
Testing #
Menu buttons and HUD values carry Semantics(identifier:) values from GalleryKeys (gallery_start_button, gallery_pause_button, gallery_final_score, gallery_hud_score, ...) and per game keys (RunnerKeys, MatchKeys, RhythmKeys). The repository has a Maestro suite that plays every game on iOS and Android: apps/example/maestro.
Build your own game #
Extend GalleryFlameGame (gameplay) and GalleryGame (public description) from flame_gallery_core; the host page, menus, pause handling and results come for free.
License #
MIT




