https://github.com/vicajilau/genui
Zero-boilerplate code generation for the official flutter/genui package. Use @generativeUI to automatically extract JSON schemas and build CatalogItems at compile-time.
https://github.com/vicajilau/genui
dart flutter generative-ui genkit genui
Last synced: 4 days ago
JSON representation
Zero-boilerplate code generation for the official flutter/genui package. Use @generativeUI to automatically extract JSON schemas and build CatalogItems at compile-time.
- Host: GitHub
- URL: https://github.com/vicajilau/genui
- Owner: vicajilau
- License: mit
- Created: 2026-06-02T07:27:44.000Z (26 days ago)
- Default Branch: main
- Last Pushed: 2026-06-15T11:56:51.000Z (13 days ago)
- Last Synced: 2026-06-15T12:23:46.864Z (13 days ago)
- Topics: dart, flutter, generative-ui, genkit, genui
- Language: Dart
- Homepage: https://vicajilau.github.io/genui/
- Size: 445 KB
- Stars: 2
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# GenUI: Code Generation for Flutter Generative UI

The developer experience (DX) companion for the official Google **Generative UI (GenUI)** ecosystem in Flutter.
GenUI code generation automatically extracts data schemas and generates type-safe builders for your widgets at compile time. Instead of manually writing JSON schemas and writing repetitive catalog adapters, you can focus on building standard Flutter widgets.
---
## 🚀 Key Features
* **Zero-Boilerplate Catalogs:** Simply decorate your Flutter widget with `@generativeUI`. The build system automatically handles schema mapping and widget instantiation.
* **Compile-Time Introspection:** Uses Dart's AST (Abstract Syntax Tree) and `build_runner` to extract property constraints, avoiding runtime reflection overhead.
* **Two-Phase Code Generation:** Automatically generates highly optimized local component schemas (`CatalogItem`s) AND assembles a central `genui_registry.g.dart` catalog index. No manual wiring required.
* **Automatic Event Mapping:** Event callback properties (like `VoidCallback`) are automatically mapped to dispatch A2UI events (`dispatchEvent(UserActionEvent)`), sending widget states back to the LLM.
* **Seamless Integration:** Built directly on top of the official `package:genui` and `package:json_schema_builder`.
---
## ✨ The Developer Experience (DX)
1. **Zero Boilerplate:** Decorate your Flutter widget with `@generativeUI`.
2. **Auto-Discovery:** You don't need to manually register your widgets into a massive list. The `genui_builder` crawls your project and creates a single `globalGenUICatalog` containing everything.
3. **Fully Type-Safe:** Automatically casts `itemContext.data` values to your widget constructor fields, preventing type mismatches at runtime.
---
## 📁 Workspace Structure
This monorepo utilizes Dart Pub Workspaces and Melos to ensure clean dependency graphs.
| Package | Description |
| --- | --- |
| [`genui_annotations`](./packages/genui_annotations) | Lightweight package containing the `@generativeUI` and `@GenerativeUI` annotations. |
| [`genui_builder`](./packages/genui_builder) | The AST code generator using `build_runner` and `analyzer` to extract component schemas and build the global catalog index at compile time. |
| [`example`](./example) | The playground Flutter app demonstrating the integration with Google's official `package:genui` Surface and SurfaceController. |
---
## 🛠️ Getting Started
### Prerequisites
Ensure you have **Dart SDK ^3.12.0** or Flutter SDK installed. You also need Melos activated globally.
```bash
# Activate Melos globally
dart pub global activate melos
```
### Setup the Workspace
Clone the repository and resolve dependencies:
```bash
git clone https://github.com/vicajilau/genui.git
cd genui
# Link dependencies natively across the workspace
flutter pub get
```
### Code Generation
To generate your UI schemas and the global registry, run:
```bash
# Triggers code generation across all workspace packages
melos run build_runner
```
---
## 📖 Usage Example
### 1. Annotate your Widgets
Import the annotations package, decorate your widget, and include the `.genui.g.dart` part directive.
```dart
import 'package:flutter/material.dart';
import 'package:genui/genui.dart';
import 'package:genui_annotations/genui_annotations.dart';
import 'package:json_schema_builder/json_schema_builder.dart';
part 'user_card.genui.g.dart';
@generativeUI
class UserCard extends StatelessWidget {
final String username;
final String role;
const UserCard({
super.key,
required this.username,
required this.role,
});
@override
Widget build(BuildContext context) {
return Card(
child: ListTile(
title: Text(username),
subtitle: Text(role),
),
);
}
}
```
### 2. Consume the Global Catalog
Run the code generator. GenUI will automatically compile your widget into a `CatalogItem` and export it to a global `Catalog` in `lib/genui_registry.g.dart`.
```dart
import 'package:flutter/material.dart';
import 'package:genui/genui.dart';
// Auto-generated by GenUI Builder
import 'genui_registry.g.dart';
void main() {
// Inject the global catalog into the official SurfaceController
// Note: globalGenUICatalog automatically includes Google's official layout elements (Row, Column, Text, etc.) alongside your custom widgets!
final controller = SurfaceController(catalogs: [globalGenUICatalog]);
runApp(MainApp(controller: controller));
}
class MainApp extends StatelessWidget {
final SurfaceController controller;
const MainApp({super.key, required this.controller});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
// Render dynamic surfaces automatically using your catalog!
child: Surface(
surfaceContext: controller.contextFor('demo_surface'),
),
),
),
);
}
}
```
### 3. Handle Events Type-Safely
If your widget defines interactive callbacks (like `VoidCallback onToggle`), you can parse and process them cleanly using `GenUiEvent` and auto-generated event constants:
```dart
import 'package:genui_annotations/genui_annotations.dart';
// Import the generated events:
import 'widgets/user_card.genui.g.dart';
void handleWidgetEvent(String eventJson) {
final event = GenUiEvent.parse(eventJson);
if (event == null) return;
if (event.name == UserCardEvents.onToggle) {
print('UserCard clicked for component ID: ${event.sourceComponentId}');
print('Widget properties context: ${event.context}');
}
}
```
*Note: For callbacks that take arguments (e.g. `ValueChanged onChanged`), parameter names and values are automatically appended to the event's `context` map (e.g. `event.context['value']`).*
### 4. Decoupled AI Schema Sharing (e.g. Google Genkit)
GenUI supports exporting your UI component schemas in a framework-agnostic way. This is ideal if you are orchestrating your AI models in a separate Node.js, Go, or Python backend (like Google Genkit).
#### In-Memory Usage (Client-Side LLM)
If your AI runs locally on the device or if you have a Dart backend, you can fetch pre-formatted schemas directly from `genui_registry.g.dart`:
```dart
// 1. Raw Dart Map of JSON Schemas:
Map> schemas = globalGenUISchemas;
// 2. Pre-formatted Markdown list ready for LLM System Instructions:
String systemInstruction = '''
You are a GenUI assistant. You must respond using components defined here:
$globalGenUISchemasPromptDescription
''';
```
#### Static File Export (Backend Genkit/TypeScript)
To use your schemas in a separate backend repository (e.g., Node.js with Genkit), you can export the schemas to a static JSON file.
Because the generated registry transitively imports `package:flutter` (which has native graphic/engine bindings), running a standalone Dart script via `dart run` in the console will fail. Instead, we run a headless script using the `flutter test` runner, which resolves all Flutter engine bindings correctly.
To set this up in your own Flutter project:
1. **Create the export script** as a test file (e.g., `test/genui_schemas_export_test.dart`):
```dart
import 'dart:convert';
import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
import 'package:your_app_name/genui_registry.g.dart'; // Import your generated registry
void main() {
test('Export GenUI schemas to JSON', () {
final schemas = globalGenUISchemas;
final jsonString = const JsonEncoder.withIndent(' ').convert(schemas);
// Auto-detect the project root and write to build/genui_schemas.json
final envPath = Platform.environment['GENUI_EXPORT_PATH'];
final file = envPath != null && envPath.isNotEmpty
? File(envPath)
: File('build/genui_schemas.json');
file.parent.createSync(recursive: true);
file.writeAsStringSync(jsonString);
print('✓ Schemas exported to: ${file.absolute.path}');
});
}
```
2. **Trigger the export automatically** by appending it to your build command in your `pubspec.yaml` scripts or Melos tasks:
```bash
# Run build_runner, then run the test script to write the JSON schema contract
dart run build_runner build && flutter test test/genui_schemas_export_test.dart
```
By default, this will write the schema to `build/genui_schemas.json` relative to your project's root.
If you want to copy the file directly to a custom directory (e.g., to a sibling folder containing your Node.js Genkit backend), you can use the `GENUI_EXPORT_PATH` environment variable:
```bash
GENUI_EXPORT_PATH=../my-genkit-backend/src/genui_schemas.json flutter test test/genui_schemas_export_test.dart
```
---
## 📄 License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.