# Say My Frame

Say My Frame (SMF) generates Flutter apps from independent modules. You choose what the app needs, such as a router, tabs at the bottom, sign-in with Google and Apple, notifications, dependency injection, a state manager, Firebase services or screens, and `smf create` generates a Flutter project in which these pieces already work together. The routes of the screens are in the router, the tabs show the screens, the services are registered in the container, and the start-up code runs in the right order.

```bash
dart pub global activate smf_flutter_cli
smf create my_app -m home,onboarding,settings,bottom_tabs,material_theme,gen_l10n,get_it,bloc
```

[Video: smf create in a terminal: it asks for the app name and the modules, among them the onboarding screen, Google sign-in and Sign in with Apple, and the notifications, adds the modules that the chosen ones need, such as go_router, the settings screen and Firebase Authentication, asks who may use the app without an account, and generates a Flutter app with an onboarding, a start screen, sign-in with an email, Google and Apple, notifications, tabs at the bottom, a theme, two languages, get_it and BLoC](https://doc.saymyframe.com/demo/0.6/smf_create.mp4)

The video shows a run in a terminal that picks these modules by answering the questions of `smf create`, and with them [`sign_in`](https://doc.saymyframe.com/modules/sign-in.md), the screens of sign-in, with [`google_sign_in`](https://doc.saymyframe.com/modules/google-sign-in.md) and [`apple_sign_in`](https://doc.saymyframe.com/modules/apple-sign-in.md), and [`local_notifications`](https://doc.saymyframe.com/modules/local-notifications.md). Sign-in needs a Firebase project, which the run leaves for later; [Sign-in](https://doc.saymyframe.com/guides/sign-in.md) has the steps.

What you get is a regular Flutter project. It does not depend on SMF at run time, and nothing in it has to be generated again, so the code is yours from the first commit. It comes with `AGENTS.md`, a guide for the [coding agents](https://doc.saymyframe.com/guides/coding-agents.md) that work on it.

## Why modules

A module is one piece of an app, such as the router or the analytics, and modules do not know about each other. A module that shows screens says that it needs *a router*, without knowing that the router is go_router. The analytics module can follow the screens the user sees *when the app has a router*, whichever router it is. SMF calls these shared parts **roles**, and more than one module can provide the same role.

That is why any combination works: you can add or leave out a module, or swap one provider of a role for another, and the app still compiles. Continuous integration generates apps from the modules in many combinations and checks each one with `flutter analyze`.

## The modules

| Role | Modules that provide it | How many in an app |
| --- | --- | --- |
| App entry | [`flutter_core`](https://doc.saymyframe.com/modules/flutter-core.md) | always one |
| Router | [`go_router`](https://doc.saymyframe.com/modules/go-router.md) | none or one |
| Layout | [`bottom_tabs`](https://doc.saymyframe.com/modules/bottom-tabs.md) | none or one |
| Settings screen | [`settings`](https://doc.saymyframe.com/modules/settings.md) | none or one |
| Onboarding screen | [`onboarding`](https://doc.saymyframe.com/modules/onboarding.md) | none or one |
| State management | [`bloc`](https://doc.saymyframe.com/modules/bloc.md), [`riverpod`](https://doc.saymyframe.com/modules/riverpod.md) | none or one |
| Theme | [`material_theme`](https://doc.saymyframe.com/modules/material-theme.md) | none or one |
| Localization | [`gen_l10n`](https://doc.saymyframe.com/modules/gen-l10n.md) | none or one |
| Dependency injection | [`get_it`](https://doc.saymyframe.com/modules/get-it.md) | none or one |
| Events | [`event_bus`](https://doc.saymyframe.com/modules/event-bus.md) | none or one |
| Preferences | [`shared_preferences`](https://doc.saymyframe.com/modules/shared-preferences.md) | none or one |
| Notifications | [`local_notifications`](https://doc.saymyframe.com/modules/local-notifications.md) | none or one |
| Push messages | [`firebase_messaging`](https://doc.saymyframe.com/modules/firebase-messaging.md) | none or one |
| Crash reporting | [`firebase_crashlytics`](https://doc.saymyframe.com/modules/firebase-crashlytics.md) | any number |
| Analytics | [`firebase_analytics`](https://doc.saymyframe.com/modules/firebase-analytics.md) | any number |
| Authentication | [`firebase_auth`](https://doc.saymyframe.com/modules/firebase-auth.md) | none or one |

Five modules provide no role. Two are features: [`home`](https://doc.saymyframe.com/modules/home.md), a start screen, and [`sign_in`](https://doc.saymyframe.com/modules/sign-in.md), the screens of sign-in and of the account. [`firebase_core`](https://doc.saymyframe.com/modules/firebase-core.md) sets up Firebase for the other Firebase modules, and [`google_sign_in`](https://doc.saymyframe.com/modules/google-sign-in.md) and [`apple_sign_in`](https://doc.saymyframe.com/modules/apple-sign-in.md) add the ways to sign in with Google and Apple.

## Status

SMF generates apps for Flutter 3.44 or newer and Dart 3.12 or newer. It is tested on macOS, Linux and Windows.

## Where to go next

- To generate an app, [install SMF](https://doc.saymyframe.com/getting-started/installation.md), [create your first app](https://doc.saymyframe.com/getting-started/first-app.md) and [take a tour of it](https://doc.saymyframe.com/getting-started/generated-app.md).
- To pick modules, read [Choosing modules](https://doc.saymyframe.com/guides/choosing-modules.md) and the [`smf create` reference](https://doc.saymyframe.com/guides/smf-create.md).
- To see how it works, read about [the module model](https://doc.saymyframe.com/concepts/module-model.md) and [the generation pipeline](https://doc.saymyframe.com/concepts/pipeline.md).
- To write a module of your own, start with [Extending SMF](https://doc.saymyframe.com/extending.md).
- To help build SMF, see [Contributing](https://doc.saymyframe.com/contributing.md).
