A powerful Flutter package for implementing Server-Driven UI (SDUI) with both JSON and gRPC support.
Server-Driven UI is an architectural pattern where the UI layout and content definitions come from a backend server rather than being hardcoded in the client application. This approach enables:
- Dynamic UI updates without app store releases
 - A/B testing and feature flagging at the UI level
 - Consistent UI across platforms
 - Faster iteration cycles for UI changes
 
- Render UI dynamically from server-provided definitions
 - Support for essential Flutter widgets (Text, Column, Row, Container, etc.)
 - JSON parsing for server responses
 - gRPC support for efficient, type-safe communication
 - Protocol Buffers for structured data exchange
 - Easy-to-use client API
 - Customizable error handling and loading states
 
Add the package to your pubspec.yaml:
dependencies:
  flutter_glimpse: ^0.0.1# For devs
dependencies:
  flutter_glimpse:
    path: path/to/flutter_glimpseOr use the Flutter CLI:
flutter pub add flutter_glimpseImport the package in your Dart code:
import 'package:flutter_glimpse/flutter_glimpse.dart';This package provides two approaches for implementing server-driven UI:
For efficient, type-safe server communication:
// Create a gRPC client
final client = GlimpseGrpcClient(
  host: 'your-server.com',
  port: 50051,
);
// Use the GlimpseGrpcRenderer widget
GlimpseGrpcRenderer(
  client: client,
  screenId: 'home_screen',
  loadingWidget: CircularProgressIndicator(),
  errorBuilder: (context, error) => Text('Error: $error'),
)For simpler implementation with standard HTTP requests:
// Parse Glimpse JSON to widget
dynamic json = ...; // Load your JSON
final glimpseWidget = GlimpseParser.parseJSON(json);
final flutterWidget = glimpseWidget.toFlutterWidget();You can also serialize Glimpse widgets back to JSON:
final json = GlimpseParser.toJson(glimpseWidget);And convert Flutter widgets to Glimpse (for supported types):
import 'package:flutter_glimpse/src/flutter_to_glimpse.dart';
final glimpseWidget = flutterToGlimpse(myFlutterWidget);- All core layout and display widgets are supported: 
Column,Row,Text,Image,SizedBox,Container,Scaffold,Spacer,Icon. - Adding new widgets is straightforward: implement the Glimpse widget, add proto/JSON parsing, and update the toJson and Flutter conversion logic.
 - The codebase is up-to-date, with no remaining TODOs.
 
Here's a complete example of using the gRPC renderer:
import 'package:flutter/material.dart';
import 'package:flutter_glimpse/flutter_glimpse.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Glimpse Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      home: const GlimpseDemo(),
    );
  }
}
class GlimpseDemo extends StatefulWidget {
  const GlimpseDemo({super.key});
  @override
  State<GlimpseDemo> createState() => _GlimpseDemoState();
}
class _GlimpseDemoState extends State<GlimpseDemo> {
  late GlimpseGrpcClient _grpcClient;
  String _screenId = 'home';
  @override
  void initState() {
    super.initState();
    _grpcClient = GlimpseGrpcClient(
      host: 'localhost',  // Replace with your server address
      port: 50051,        // Replace with your server port
    );
  }
  @override
  void dispose() {
    _grpcClient.dispose();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Server-Driven UI Demo'),
      ),
      body: GlimpseGrpcRenderer(
        client: _grpcClient,
        screenId: _screenId,
        loadingWidget: const Center(
          child: CircularProgressIndicator(),
        ),
        errorBuilder: (context, error) {
          return Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Icon(Icons.error, color: Colors.red, size: 48),
                SizedBox(height: 16),
                Text('Error: $error'),
                SizedBox(height: 16),
                ElevatedButton(
                  onPressed: () => setState(() {}),
                  child: Text('Retry'),
                ),
              ],
            ),
          );
        },
      ),
    );
  }
}Here's a basic example of a Dart server that provides UI definitions via gRPC:
import 'package:grpc/grpc.dart';
import 'package:flutter_glimpse/src/generated/glimpse.pb.dart';
import 'package:flutter_glimpse/src/generated/glimpse.pbgrpc.dart';
Future<void> main() async {
  final server = Server.create(
    services: [
      GlimpseServiceImpl(),
    ],
  );
  await server.serve(port: 50051);
  print('Server listening on port 50051...');
}
class GlimpseServiceImpl extends GlimpseServiceBase {
  @override
  Future<GlimpseWidgetData> getGlimpseWidget(
      ServiceCall call, GlimpseRequest request) async {
    // Return different UI based on the screenId
    switch (request.screenId) {
      case 'home':
        return _createHomeScreen();
      default:
        return _createErrorScreen();
    }
  }
  GlimpseWidgetData _createHomeScreen() {
    return GlimpseWidgetData()
      ..type = WidgetType.SCAFFOLD
      ..body = (GlimpseWidgetData()
        ..type = WidgetType.COLUMN
        ..children.addAll([
          GlimpseWidgetData()
            ..type = WidgetType.CONTAINER
            ..padding = (EdgeInsetsData()..all = 16)
            ..child = (GlimpseWidgetData()
              ..type = WidgetType.TEXT
              ..stringAttributes['text'] = 'Welcome to Server-Driven UI!'
              ..textStyle = (TextStyleData()
                ..fontSize = 22
                ..fontWeight = 'bold')),
          GlimpseWidgetData()
            ..type = WidgetType.TEXT
            ..stringAttributes['text'] = 'This UI is rendered from gRPC data'
        ]));
  }
}The package currently supports these Flutter widgets:
ScaffoldContainerColumnRowTextImageSizedBoxSpacerIcon
The package uses Protocol Buffers to define the data structures for gRPC communication. Here's a simplified version of the main message types:
message GlimpseWidgetData {
  WidgetType type = 1;
  map<string, string> string_attributes = 2;
  map<string, double> double_attributes = 3;
  map<string, bool> bool_attributes = 4;
  // Complex nested attributes
  TextStyleData text_style = 6;
  EdgeInsetsData padding = 7;
  // Children widgets
  repeated GlimpseWidgetData children = 12;
  GlimpseWidgetData child = 13;
  // Scaffold specific parts
  GlimpseWidgetData app_bar = 14;
  GlimpseWidgetData body = 15;
}
service GlimpseService {
  rpc GetGlimpseWidget (GlimpseRequest) returns (GlimpseWidgetData);
}If you need to regenerate the Dart files from the proto definitions:
- Install the Protocol Buffer compiler using the provided scripts:
 
# Windows
pwsh ./tool/setup_protoc.ps1
# Generate the Protobuf files
pwsh ./tool/generate_protos.ps1- Basic widget support
 - gRPC implementation
 - JSON implementation
 - Interactive widgets (buttons, forms)
 - More advanced widget support
 
See ADDING_WIDGET.md for instructions on how to add a new widget to the Glimpse package.
This project is licensed under the LICENSE file in the repository.
| Jothish Kamal | Rujin Devkota | Adhavan K | 
Made with ❤ by GDSC-VIT