This guide explains the overall structure of a Stac project. It covers where the UI is defined, how parsers are organized, and how themes and routes fit together.
Basic Structure
├─ flutter_project/
├── lib/
│ ├── app/ # Feature-specific code (optional)
│ ├── default_stac_options.dart # Default StacOptions for Stac configuration
│ └── main.dart # Entry point for stac initialize
├── stac/
│ └── hello_world.dart # Stac widgets
├── pubspec.lock
└── pubspec.yaml
Key Files
default_stac_options.dart
Contains the StacOptions configuration for your project, including project name and ID.
import 'package:stac/stac_core.dart';
StacOptions get defaultStacOptions => StacOptions(
name: 'your-project-name',
projectId: 'your-project-id',
description: 'Optional project description',
);
main.dart
Entry point for the Flutter app where Stac is initialized. Custom parsers are registered here:
import 'package:flutter/material.dart';
import 'package:stac/stac.dart';
import 'default_stac_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Stac.initialize(
options: defaultStacOptions,
parsers: [], // Custom widget parsers
actionParsers: [], // Custom action parsers
);
runApp(const MyApp());
}
stac/ folder
Contains your Stac widget definitions written in Dart. Each file can contain one or more @StacScreen annotated functions.
Extended Structure
For larger projects, here’s a recommended structure:
├─ flutter_project/
├── lib/
│ ├── app/
│ │ ├── parsers/ # Custom widget and action parsers
│ │ │ ├── widgets/
│ │ │ │ └── custom_chart_parser.dart
│ │ │ └── actions/
│ │ │ └── analytics_action_parser.dart
│ │ └── theme/
│ │ └── app_theme.dart # Theme configuration
│ ├── default_stac_options.dart
│ └── main.dart
├── stac/
│ ├── screens/ # Organized by feature
│ │ ├── home/
│ │ │ └── home_screen.dart
│ │ ├── profile/
│ │ │ └── profile_screen.dart
│ │ └── settings/
│ │ └── settings_screen.dart
│ ├── components/ # Reusable UI components
│ │ ├── header.dart
│ │ └── footer.dart
│ └── .build/ # Generated JSON (auto-created)
│ ├── home_screen.json
│ ├── profile_screen.json
│ └── settings_screen.json
├── pubspec.lock
└── pubspec.yaml
Build Output
When you run stac build or stac deploy, the Dart files are converted to JSON and placed in stac/.build/:
stac/
├── home_screen.dart # Your Dart source
└── .build/
└── home_screen.json # Generated JSON output
The .build folder is automatically created and should typically be added to .gitignore since it’s generated from your Dart source files.
Custom Parsers
Custom widget and action parsers extend Stac’s capabilities. Place them in a dedicated folder and register them in Stac.initialize:
// lib/app/parsers/widgets/custom_chart_parser.dart
import 'package:stac_framework/stac_framework.dart';
class CustomChartParser extends StacParser<CustomChart> {
@override
String get type => 'customChart';
@override
CustomChart getModel(Map<String, dynamic> json) {
return CustomChart.fromJson(json);
}
@override
Widget parse(BuildContext context, CustomChart model) {
return MyChartWidget(data: model.data);
}
}
// lib/main.dart
await Stac.initialize(
options: defaultStacOptions,
parsers: [
CustomChartParser(),
],
actionParsers: [
AnalyticsActionParser(),
],
);
Theme Configuration
Themes can be configured through Stac Cloud or locally via StacApp:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StacApp(
title: 'My App',
theme: StacAppTheme(name: 'light_theme'),
darkTheme: StacAppTheme(name: 'dark_theme'),
themeMode: ThemeMode.system,
homeBuilder: (context) => Stac(routeName: 'home_screen'),
);
}
}
You can also use JSON-based themes:
StacApp(
theme: StacAppTheme.json(payload: myThemeJson),
// ...
)
Multiple Screens Organization
For apps with many screens, organize by feature or route:
stac/
├── auth/
│ ├── login_screen.dart
│ ├── signup_screen.dart
│ └── forgot_password_screen.dart
├── dashboard/
│ ├── home_screen.dart
│ └── stats_screen.dart
└── settings/
├── settings_screen.dart
└── profile_screen.dart
Each file uses the @StacScreen annotation:
@StacScreen(screenName: 'login')
StacWidget loginScreen() {
return StacScaffold(
body: StacCenter(
child: StacText(data: 'Login'),
),
);
}