Skip to main content

flame_gallery 0.1.0 copy "flame_gallery: ^0.1.0" to clipboard
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 #

pub package CI License: MIT

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.show pushes a full screen route with start, pause and game over menus, and completes with a GameResult.
  • 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 flutter and flame. No state management or codegen packages are forced on you.
  • Testable. Stable Semantics identifiers 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

0
likes
160
points
0
downloads
screenshot

Documentation

API reference

Publisher

verified publishervbxtech.app

Weekly Downloads

Drop-in, brandable 2D mini games (slice, endless runner, match-3, rhythm) for any Flutter app, opened with one FlameGallery.show call.

Repository (GitHub)
View/report issues

Topics

#flame #game #minigame #gamification #widget

License

MIT (license)

Dependencies

flame_gallery_core, flame_gallery_match, flame_gallery_rhythm, flame_gallery_runner, flame_gallery_slice, flutter

More

Packages that depend on flame_gallery