--- name: "generating-flutter-ui" description: "Generative UI (GenUI) for Flutter using AI models like Google Gemini, Anthropic Claude, or OpenAI via the genui package. Use this skill when building dynamic AI-driven interfaces, conversational UI flows, server-rendered screen layouts, LLM-powered dashboards, chat-based UI generation, or implementing prompt-to-UI systems. Supports AI-generated widgets, reactive data binding, ContentGenerator integration, and A2uiMessageProcessor for real-time UI updates from AI responses. Ideal for apps where UI structure is determined by AI/LLM output rather than hardcoded layouts." metadata: last_modified: "2026-04-01 14:35:00 (GMT+8)" --- # Flutter Generative UI (GenUI) Best Practices ## Goal Implement a dynamic user interface generated by AI using the [genui](https://pub.dev/packages/genui) package. This is the recommended approach when an application needs to build reactive screens or components directly from AI responses without hardcoding the layout. ## Instructions The `genui` package orchestrates a conversational loop between the user, the AI (via `ContentGenerator`), and the Flutter UI (via `A2uiMessageProcessor` and `DataModel`). ### 1. Project Setup Add the necessary packages to your `pubspec.yaml`: ```bash flutter pub add genui # For Gemini integration via Firebase: flutter pub add genui_firebase_ai ``` If targeting macOS/iOS, enable outbound network requests in entitlements: ```xml com.apple.security.network.client ``` ### 2. Core Integration Structure To connect your Flutter application to the AI agent, you need to instantiate three main components: 1. **`A2uiMessageProcessor`**: Handles the UI side, translating AI messages into UI actions. Supply it with a `Catalog` of widgets the AI is allowed to use. 2. **`ContentGenerator`**: Handles communication with the AI. Supply it with system instructions and tools. 3. **`GenUiConversation`**: The facade coordinating the processor and generator. **Example Setup in a StatefulWidget:** ```dart import 'package:flutter/material.dart'; import 'package:genui/genui.dart'; import 'package:genui_firebase_ai/genui_firebase_ai.dart'; class GenUIPage extends StatefulWidget { const GenUIPage({super.key}); @override State createState() => _GenUIPageState(); } class _GenUIPageState extends State { late final A2uiMessageProcessor _a2uiMessageProcessor; late final GenUiConversation _genUiConversation; @override void initState() { super.initState(); // 1. Initialize Message Processor with predefined catalog widgets _a2uiMessageProcessor = A2uiMessageProcessor( catalogs: [CoreCatalogItems.asCatalog()], ); // 2. Initialize Content Generator (e.g., Firebase AI / Gemini) final contentGenerator = FirebaseAiContentGenerator( catalog: CoreCatalogItems.asCatalog(), systemInstruction: ''' You are an AI assistant. You must generate UI by responding with JSON matching the provided widget schemas. Always output valid UI structures. ''', tools: _a2uiMessageProcessor.getTools(), ); // 3. Orchestrate the Conversation _genUiConversation = GenUiConversation( a2uiMessageProcessor: _a2uiMessageProcessor, contentGenerator: contentGenerator, // Implement your handlers for rendering generated surfaces onSurfaceAdded: (surfaceId) { /* Handle surface creation */ }, onSurfaceDeleted: (surfaceId) { /* Handle surface deletion */ }, onTextResponse: (text) { /* Optional: show text explicitly */ }, onError: (error) { /* Handle generation errors */ }, ); } @override void dispose() { _genUiConversation.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // UI Implementation interacting with _genUiConversation.sendRequest() return const Scaffold(); } } ``` ### 3. Data Model & Data Binding A core philosophy of `genui` is utilizing a central `DataModel`. Widgets don't manage their own dynamic state; instead, they bind to paths within the `DataModel`. When creating custom widgets to add to your `Catalog`, ensure they react to the data context: ```dart // The AI will generate JSON like: // { "Text": { "text": { "literalString": "Hello" } } } // OR // { "Text": { "text": { "path": "/user/welcome_message" } } } ``` * **literalString**: Static data directly from the AI. * **path**: A reference to a location in the `DataModel`. Updates to this path automatically rebuild any widgets bound to it. Input widgets (like `TextField`) should directly update this `DataModel`. ### 4. Customizing the Catalog To extend GenUI beyond the `CoreCatalogItems`, define your own `CatalogItem`s and provide them to both the `A2uiMessageProcessor` and the `ContentGenerator`. This tells the AI what Custom Widgets are available and what parameters they accept. ## Constraints * **Architecture Scope**: Do not use `genui` for static screens or standard layouts. It should be reserved exclusively for features needing generative or highly dynamic, AI-driven UI presentation. * **State Management**: Within GenUI components, prefer the unified `DataModel` reactivity over local `setState` for data shared with the AI. * **Error Handling**: Always ensure `onError` in `GenUiConversation` is handled appropriately, as AI responses can sometimes fail parsing or violate catalog schemas.