SkillAgentSearch skills...

flutter-pre-caching

Use when preloading fonts, asset/network images, Lottie/Rive animations, local JSON/config, warming initial API data, or optimizing Flutter Web startup.

Install / Use

npx skills add evanca/flutter-ai-rules --skill flutter-pre-caching

Installs into whichever agent you are using.

About this skill
📄

SKILL.md

Installable skill definition

Quality Score

92/100

Supported Platforms

Universal

Our assessment of flutter-pre-caching

flutter-pre-caching scores 92/100 on our quality scale, 888th of 4,634 Development & Engineering skills we index (top 20%).

Its SKILL.md is 18 KB long, well organised into 31 sections with 42 code examples: a thorough specification that gives an agent plenty to work with.

It has 646 GitHub stars, a meaningful sign that others use it.

Substance
30/30
Structure
20/20
Description
15/15
Adoption
12/20
Freshness
15/15

Maintenance, license and trust

  • The repository was last updated 19 days ago, so flutter-pre-caching is actively maintained.
  • It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
  • Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

flutter-pre-caching compared with similar skills

All 4 of these similar skills score higher than flutter-pre-caching; compare them before choosing.

SkillScoreStarsUpdatedFormat
flutter-pre-caching (this skill)by evanca9264619d agoSKILL.md
Agent-Reachby Panniantong10089.8k18d agoCLAUDE.md
headroomby headroomlabs-ai10074.4ktodayCLAUDE.md
ai-job-searchby MadsLorentzen10044.9ktodayCLAUDE.md
claude-howtoby luongnv8910041.7k3d agoCLAUDE.md

Frequently asked questions

How do I install flutter-pre-caching?
Run npx skills add evanca/flutter-ai-rules --skill flutter-pre-caching. The install tabs above show the steps for each supported agent.
Which AI agents does flutter-pre-caching work with?
It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
Is flutter-pre-caching safe to use?
It is MIT-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is flutter-pre-caching still maintained?
The repository was last updated 19 days ago, so flutter-pre-caching is actively maintained.

name: flutter-pre-caching description: "Use when preloading fonts, asset/network images, Lottie/Rive animations, local JSON/config, warming initial API data, or optimizing Flutter Web startup." license: MIT

Pre-caching in Flutter and Flutter Web

Pre-caching helps avoid jank, loading flashes, font swaps, and delayed first renders.

The key rule:

Pre-cache only what the user will likely see in the next 1 to 2 screens.

Do not pre-cache the whole app. That can slow startup and waste memory.


1. Google Fonts

Runtime Google Fonts preloading

Use GoogleFonts.pendingFonts() to load the font variants before showing text.

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

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

  @override
  State<ExampleSimple> createState() => _ExampleSimpleState();
}

class _ExampleSimpleState extends State<ExampleSimple> {
  late final Future<List<void>> googleFontsPending;

  @override
  void initState() {
    super.initState();

    googleFontsPending = GoogleFonts.pendingFonts([
      GoogleFonts.poppins(),
      GoogleFonts.montserrat(fontStyle: FontStyle.italic),
    ]);
  }

  @override
  Widget build(BuildContext context) {
    final pushButtonTextStyle = GoogleFonts.poppins(
      textStyle: Theme.of(context).textTheme.headlineMedium,
    );

    final counterTextStyle = GoogleFonts.montserrat(
      fontStyle: FontStyle.italic,
      textStyle: Theme.of(context).textTheme.displayLarge,
    );

    return FutureBuilder<List<void>>(
      future: googleFontsPending,
      builder: (context, snapshot) {
        if (snapshot.connectionState != ConnectionState.done) {
          return const SizedBox();
        }

        return Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'You have pushed the button this many times:',
              style: pushButtonTextStyle,
            ),
            Text(
              '0',
              style: counterTextStyle,
            ),
          ],
        );
      },
    );
  }
}

Production recommendation

For production and offline support, prefer bundling critical fonts as assets.

flutter:
  fonts:
    - family: AppFont
      fonts:
        - asset: assets/fonts/AppFont-Regular.ttf
        - asset: assets/fonts/AppFont-Bold.ttf
          weight: 700

Use it in the app theme:

MaterialApp(
  theme: ThemeData(
    fontFamily: 'AppFont',
  ),
)

2. Asset images

Use precacheImage for images that appear soon.

@override
void didChangeDependencies() {
  super.didChangeDependencies();

  precacheImage(
    const AssetImage('assets/images/header.png'),
    context,
  );
}

Then use the image normally:

Image.asset('assets/images/header.png')

3. Network images

Use precacheImage with NetworkImage.

@override
void didChangeDependencies() {
  super.didChangeDependencies();

  precacheImage(
    const NetworkImage('https://example.com/image.png'),
    context,
  );
}

Then use it normally:

Image.network('https://example.com/image.png')

Important: precacheImage warms Flutter’s in-memory image cache. It does not provide long-term offline caching.

For disk caching, use a package like cached_network_image:

dependencies:
  cached_network_image: ^latest

Example:

CachedNetworkImage(
  imageUrl: 'https://example.com/image.png',
)

4. Multiple image preloading

@override
void didChangeDependencies() {
  super.didChangeDependencies();

  final images = <ImageProvider>[
    const AssetImage('assets/images/header.png'),
    const AssetImage('assets/images/avatar.png'),
    const NetworkImage('https://example.com/banner.png'),
  ];

  for (final image in images) {
    precacheImage(image, context);
  }
}

5. Waiting until images are ready

precacheImage returns a Future<void>, so you can wait before rendering the real UI.

late Future<void> _preloadImagesFuture;

@override
void didChangeDependencies() {
  super.didChangeDependencies();

  _preloadImagesFuture = Future.wait([
    precacheImage(
      const AssetImage('assets/images/header.png'),
      context,
    ),
    precacheImage(
      const NetworkImage('https://example.com/banner.png'),
      context,
    ),
  ]);
}

@override
Widget build(BuildContext context) {
  return FutureBuilder<void>(
    future: _preloadImagesFuture,
    builder: (context, snapshot) {
      if (snapshot.connectionState != ConnectionState.done) {
        return const CircularProgressIndicator();
      }

      return Column(
        children: [
          Image.asset('assets/images/header.png'),
          Image.network('https://example.com/banner.png'),
        ],
      );
    },
  );
}

[!NOTE] Use didChangeDependencies, not initState, when you need context for precacheImage.


6. What should normally be pre-cached on app start?

Good candidates:

  • App logo
  • First screen hero image
  • First visible background image
  • Current user avatar
  • First visible card/list images
  • Main font variants
  • Small local config files
  • Translations needed for first paint
  • First API request
  • Lottie/Rive animation shown immediately

Bad candidates:

  • All product images
  • All gallery images
  • All remote feed images
  • All icons in the app
  • All route images
  • Every image from every screen
  • Large animations not shown immediately

7. Practical app-start preloader

class AppPreloader {
  const AppPreloader();

  Future<void> preload(BuildContext context) async {
    await Future.wait([
      _precacheImages(context),
      _loadCriticalAssets(),
      _warmUpInitialData(),
    ]);
  }

  Future<void> _precacheImages(BuildContext context) {
    return Future.wait([
      precacheImage(
        const AssetImage('assets/images/home_hero.png'),
        context,
      ),
      precacheImage(
        const AssetImage('assets/images/logo.png'),
        context,
      ),
    ]);
  }

  Future<void> _loadCriticalAssets() async {
    await rootBundle.loadString('assets/config/app_config.json');
  }

  Future<void> _warmUpInitialData() async {
    // Example:
    // await userRepository.getCurrentUser();
  }
}

Usage:

late Future<void> _preloadFuture;

@override
void didChangeDependencies() {
  super.didChangeDependencies();

  _preloadFuture = const AppPreloader().preload(context);
}

With FutureBuilder:

@override
Widget build(BuildContext context) {
  return FutureBuilder<void>(
    future: _preloadFuture,
    builder: (context, snapshot) {
      if (snapshot.connectionState != ConnectionState.done) {
        return const SplashScreen();
      }

      return const HomeScreen();
    },
  );
}

8. Local JSON / config preloading

Useful for feature flags, local app config, mock data, translations, or onboarding content.

import 'package:flutter/services.dart';

final configJson = await rootBundle.loadString(
  'assets/config/app_config.json',
);

Example:

class AppConfigLoader {
  Future<String> load() {
    return rootBundle.loadString('assets/config/app_config.json');
  }
}

9. Initial API request warm-up

This is not pre-caching in the Flutter image-cache sense, but it is often the most useful startup optimization.

final userFuture = userRepository.getCurrentUser();
final dashboardFuture = dashboardRepository.getDashboard();

Example:

class StartupData {
  const StartupData({
    required this.user,
    required this.dashboard,
  });

  final User user;
  final Dashboard dashboard;
}

Future<StartupData> loadStartupData() async {
  final results = await Future.wait([
    userRepository.getCurrentUser(),
    dashboardRepository.getDashboard(),
  ]);

  return StartupData(
    user: results[0] as User,
    dashboard: results[1] as Dashboard,
  );
}

10. Lottie preloading

If the animation appears immediately, preload it.

final composition = await AssetLottie(
  'assets/animations/success.json',
).load();

Use this only for animations shown early. Avoid preloading many large animations on app start.


11. Rive preloading

Rather than triggering the asset load during a build (which causes jank), preload the RiveFile byte data in advance:

import 'package:flutter/services.dart';
import 'package:rive/rive.dart';

// Preload the RiveFile
final data = await rootBundle.load('assets/animations/character.riv');
final riveFile = RiveFile.import(data);

// Display using direct constructor to avoid initialization delays:
RiveAnimation.direct(riveFile);

This ensures that the animation renders immediately upon widget mount.


12. Shader warm-up

Most apps do not need this. It can help if you have:

  • Heavy custom painting
  • Complex transitions
  • Known animation jank
  • Older rendering paths

Basic shape:

class CustomShaderWarmUp extends ShaderWarmUp {
  @override
  void warmUpOnCanvas(Canvas canvas) {
    final paint = Paint();

    canvas.drawRect(
      const Rect.fromLTWH(0, 0, 100, 100),
      paint,
    );
  }
}

Then set it before runApp:

void main() {
  PaintingBinding.instance.shaderWarmUp = CustomShaderWarmUp();

  runApp(const MyApp());
}

Use this only when profiling shows shader compilation jank.


13. Flutter Web: different mindset

On Flutter Web, think less:

  • Pre-cache everything in memory

Think more:

  • Make the browser download key files early
  • Warm Flutter cache only for first-screen assets
  • Avoid surprise font fallback downloads
  • Avoid loading huge assets before first paint

14. Flutter Web image preload

For critical first-screen images, use both browser preload and Flutter precacheImage.

In web/index.html:

<link
  rel="preload"
  href="assets/assets/images/home_hero.png"
  as="image"
>

In Flutter:

await precacheImage(
  const AssetImage('assets/images/home_hero.png'),
  context,
);

Why both?

  • HTML preload starts the browser download earlier.
  • precacheImage warms Flutter's image cache.

15. Flutter Web network image preload

In web/index.html:

<link
  rel="preload"
  href="https://example.com/banner.png"
  as="image"
>

In Flutter:

await precacheImage(
  const NetworkImage('https://example.com/banner.png'),
  context,
);

Only do this for images the user is almost guaranteed to see.


16. Flutter Web font preload

Declare the font in pubspec.yaml:

flutter:
  fonts:
    - family: AppFont
      fonts:
        - asset: assets/fonts/AppFont-Regular.ttf
        - asset: assets/fonts/AppFont-Bold.ttf
          weight: 700

Preload the critical font in web/index.html:

<link
  rel="preload"
  href="assets/assets/fonts/AppFont-Regular.ttf"
  as="font"
  type="font/ttf"
  crossorigin
>

Use it in Flutter:

ThemeData(
  fontFamily: 'AppFont',
)

Usually preload:

  • Regular
  • Bold
  • Maybe medium

Avoid preloading every weight and italic variant unless the first screen needs them.


17. Flutter Web and emojis

Emojis can trigger font fallback work.

Example:

Text('Welcome 👋 🎉')

On web, this can cause:

  • Extra font download
  • Delayed render
  • Fallback font swap
  • Blank boxes
  • Different emoji style across platforms

18. Option 1: avoid emojis on first paint

Simple and effective:

Text('Welcome')

Then show emojis after the app has loaded:

Text('Welcome 👋')

This is often the best option if emojis are decorative.


19. Option 2: bundle and preload an emoji font

Add the font to pubspec.yaml:

flutter:
  fonts:
    - family: NotoColorEmoji
      fonts:
        - asset: assets/fonts/NotoColorEmoji.ttf

Preload it in web/index.html:

<link
  rel

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars646
CategoryDevelopment
Updated19d ago
Forks67

Languages

Shell

Trust signals

100/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

No cautions