Back to skills
SkillHub ClubShip Full StackFull StackFrontendBackend

flutter-duit-bdui

Integrate Duit framework into Flutter applications including setup, driver configuration, HTTP/WebSocket transports, custom widgets, and themes. Use when integrating backend-driven UI, configuring Duit, or adding Duit to Flutter applications.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
85
Hot score
93
Updated
March 20, 2026
Overall rating
C2.6
Composite score
2.6
Best-practice grade
B80.4

Install command

npx @skill-hub/cli install madteacher-mad-agents-skills-flutter-duit-bdui

Repository

MADTeacher/mad-agents-skills

Skill path: flutter-duit-bdui

Integrate Duit framework into Flutter applications including setup, driver configuration, HTTP/WebSocket transports, custom widgets, and themes. Use when integrating backend-driven UI, configuring Duit, or adding Duit to Flutter applications.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack, Frontend, Backend.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: MADTeacher.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install flutter-duit-bdui into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/MADTeacher/mad-agents-skills before adding flutter-duit-bdui to shared team environments
  • Use flutter-duit-bdui for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: flutter-duit-bdui
description: Integrate Duit framework into Flutter applications including setup, driver configuration, HTTP/WebSocket transports, custom widgets, and themes. Use when integrating backend-driven UI, configuring Duit, or adding Duit to Flutter applications.
---

# Fluttter Duit Backend-driven UI

## Overview

Duit enables backend-driven UI in Flutter applications. The server controls both data and layout via JSON, allowing UI updates without app releases.

## Quick Start

1. Add dependency to pubspec.yaml
2. Initialize DuitRegistry (optional: with themes/custom widgets)
3. Create XDriver (HTTP, WebSocket, or static)
4. Wrap UI in DuitViewHost
5. Server sends JSON layouts → Duit renders them

## Prerequisites

### SDK Requirements

```yaml
- Dart SDK: >=3.4.4 <4.0.0
- Flutter: >=3.24.0
```

### Add Dependency

```bash
flutter pub add flutter_duit
```

Install:

```bash
flutter pub get
```

## Basic Integration

### Minimal Setup

```dart
import 'package:flutter/material.dart';
import 'package:flutter_duit/flutter_duit.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: DuitViewHost.withDriver(
          driver: XDriver.static({
            "type": "Text",
            "id": "1",
            "attributes": {"data": "Hello, World!"},
          }),
        ),
      ),
    );
  }
}
```

### Driver Lifecycle Management

Always dispose drivers to prevent memory leaks:

```dart
class MyWidgetState extends State<MyWidget> {
  late final XDriver driver;

  @override
  void initState() {
    super.initState();
    driver = XDriver.static(/* ... */);
  }

  @override
  void dispose() {
    driver.dispose();
    super.dispose();
  }
}
```

## Transport Configuration

### HTTP Transport

Fetch layouts from REST API endpoints:

```dart
final driver = XDriver(
  transportManager: HttpTransportManager(
    options: HttpTransportOptions(
      baseUrl: 'https://api.example.com/view',
      headers: {
        'Authorization': 'Bearer $token',
        'Content-Type': 'application/json',
      },
    ),
  ),
);
```

### WebSocket Transport

Real-time bidirectional communication:

```dart
final driver = XDriver(
  transportManager: WSTransportManager(
    options: WSTransportOptions(
      url: 'wss://api.example.com/ws',
      headers: {
        'Authorization': 'Bearer $token',
      },
      reconnectInterval: Duration(seconds: 5),
      heartbeatInterval: Duration(seconds: 30),
    ),
  ),
);
```

### Static/Stub Transport

For testing or local layouts:

```dart
final driver = XDriver.static(
  layoutJson,
);
```

### Custom Decoder/Encoder

```dart
import 'dart:convert';
import 'dart:typed_data';

class CustomDecoder extends Converter<Uint8List, Map<String, dynamic>> {
  @override
  Map<String, dynamic> convert(Uint8List input) {
    // Custom decode logic
    return jsonDecode(utf8.decode(input));
  }
}

final driver = XDriver(
  transportManager: HttpTransportManager(
    options: HttpTransportOptions(
      baseUrl: 'https://api.example.com',
      decoder: CustomDecoder(),
    ),
  ),
);
```

### Custom Transport

Create your own transport implementation if needed:

```dart
class MyCustomTransportManager with TransportCapabilityDelegate {
  @override
  void linkDriver(UIDriver driver) {
    // Implement linkDriver method
  }

  @override
  Stream<Map<String, dynamic>> connect({
    Map<String, dynamic>? initialRequestData,
    Map<String, dynamic>? staticContent,
  }) async* {
    // Implement connect method
  }

  @override
  Future<Map<String, dynamic>?> executeRemoteAction(
    ServerAction action,
    Map<String, dynamic> payload,
  ) async {
    //Implement executeRemoteAction method
  }

  @override
  Future<Map<String, dynamic>?> request(
    String url,
    Map<String, dynamic> meta,
    Map<String, dynamic> body,
  ) async {
    //Implement request method
  }

  @override
  void releaseResources() {
    // Implement linkDriver method
  }
}
```

## Custom Widgets

### Create and register Custom Widget

```dart
import 'package:flutter_duit/flutter_duit.dart';

// 1. Define custom widget
class MyCustomWidget extends StatelessWidget {
  final ViewAttribute attributes;

  const MyCustomWidget({
    required this.attributes,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    final attrs = attributes.payload;
    return Container(
      child: Text(attrs.getString(key: "message")),
    );
  }
}

// 2. Create build factory fn for widget
Widget myCustomBuildFactory(ElementPropertyView model) {
    if (model.isControlled) {
        return MyCustomWidget(
            attributes: model.attributes,
        );
    } else {
        return const SizedBox.shrink();
    }
}

// 3. Register build-fn
void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  DuitRegistry.register(
    "MyCustomWidget",
    buildFactory: myCustomBuildFactory,
  );

  runApp(const MyApp());
}
```

## Components

### Components registration

Components allow you to create reusable UI templates that can be referenced by a tag and populated with dynamic data.

```dart
import 'package:flutter_duit/flutter_duit.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Define component template
  final cardComponent = {
    "tag": "CardComponent",
    "layoutRoot": {
      "type": "Container",
      "id": "cardContainer",
      "controlled": false,
      "attributes": {
        "padding": {"all": 16},
        "margin": {"all": 8},
        "decoration": {
          "borderRadius": 12,
          "color": "#FFFFFF",
          "boxShadow": [
            {
              "color": "#00000033",
              "blurRadius": 6,
              "offset": {"dx": 0, "dy": 2},
            },
          ],
        },
      },
      "children": [
        {
          "type": "Text",
          "id": "cardTitle",
          "controlled": false,
          "attributes": {
            "data": {
              "style": {
                "fontSize": 18,
                "fontWeight": "w600",
                "color": "#333333",
              },
            },
            "refs": [
              {
                "objectKey": "title",
                "attributeKey": "data",
              },
            ],
          },
        },
        {
          "type": "Text",
          "id": "cardDescription",
          "controlled": false,
          "attributes": {
            "data": {
              "style": {
                "fontSize": 14,
                "color": "#666666",
              },
            },
            "refs": [
              {
                "objectKey": "description",
                "attributeKey": "data",
              },
            ],
          },
        },
      ],
    },
  };

  // Register the component
  await DuitRegistry.registerComponents([cardComponent]);

  runApp(const MyApp());
}

// Usage in JSON layout from server:
// {
//   "type": "Component",
//   "id": "card1",
//   "tag": "CardComponent",
//   "data": {
//     "title": "Hello World",
//     "description": "This is a card component"
//   }
// }
```

**Key concepts:**

- **tag**: Unique identifier for the component
- **layoutRoot**: Root element of the component template
- **refs**: References to dynamic data passed via the `data` field
- **objectKey**: Key in the `data` object
- **attributeKey**: Attribute in the widget to bind to
- **defaultValue**: Optional default value if data key is missing

You can register multiple components at once:

```dart
await DuitRegistry.registerComponents([
  cardComponent,
  buttonComponent,
  listItemComponent,
]);
```

## When to Use This Skill

Use this skill when:

- Integration flutter_duit library into project
- Custom widet creation
- Components registration
- Basic framework behavior overriding via capabilities implementation
- Need help with the framework API

## Resources

### Reference Documentation

- [capabilities.md](./references/capabiliteis.md) — Notes about capability-based design and core framework parts overriding
- [troubleshooting.md](./references/troubleshooting.md) - Notes about common issues in framework integration
- [environvent_vars.md](./references//environment_vars.md) — Notes about avalilable env variables and its usage
- [public_api.md](./references/public_api.md) — Notes about driver public API
- <https://duit.pro/docs/en> — official documentation site


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### references/capabiliteis.md

```markdown
# About Duit capability-based API design

Duit framework uses a capability-based architecture that allows developers to customize and extend core functionality through modular delegates. This design pattern separates concerns and provides flexibility in how different aspects of the framework are implemented.

## Available Capabilities

The flutter_duit package provides a concrete implementation for each delegate:

| Delegate | Purpose |
|----------|---------|
| `ViewModelCapabilityDelegate` | View model management, UI events, layout structure parsing |
| `TransportCapabilityDelegate` | Transport layer (HTTP, WebSocket, static content) |
| `ServerActionExecutionCapabilityDelegate` | Server action execution and event handling |
| `UIControllerCapabilityDelegate` | UI element controller management (TextField, Checkbox, etc.) |
| `FocusCapabilityDelegate` | Focus management and element navigation |
| `ScriptingCapabilityDelegate` | Embedded script execution |
| `LoggingCapabilityDelegate` | Logging with support for different levels |
| `NativeModuleCapabilityDelegate` | Native code interaction via MethodChannel |

## Creating Custom Implementations

To create a custom capability implementation, simply create a class with the corresponding mixin:

```dart
final class MyCustomFocusManager with FocusCapabilityDelegate {
  late final UIDriver _driver;

  @override
  void linkDriver(UIDriver driver) => _driver = driver;

  @override
  void requestFocus(String nodeId) {
    // Custom focus management logic
  }

  @override
  void releaseResources() {
    // Resource cleanup
  }

  // Implementation of remaining methods...
}
```

## Best Practices

1. **Always call `linkDriver()`** when implementing custom capabilities to enable communication with the driver
2. **Implement `releaseResources()`** to clean up resources (close connections, cancel streams, etc.)
3. **Use proper error handling** and log errors via `driver.logError()`
4. **Keep capabilities focused** on a single responsibility
5. **Document custom implementations** for maintainability

---

## Conclusion

Duit's capability-based API provides a powerful and flexible architecture for building backend-driven UI applications. By understanding and customizing capabilities, you can:

- Extend functionality without modifying core framework code
- Optimize for specific use cases (mobile, web, embedded)
- Integrate with existing systems (analytics, logging, authentication)
- Add platform-specific features (native modules, JS execution)
- Improve testing and debugging capabilities

The modular design makes Duit adaptable to various requirements while maintaining a clean separation of concerns.

```

### references/troubleshooting.md

```markdown
# Troubleshooting

## Common Issues

**Widget not rendering:**

- Check widget type is registered (for custom widgets)
- Verify JSON structure matches expected format
- Ensure `id` is unique across layout

**Driver initialization failing:**

- Check network connectivity
- Verify base URL and headers
- Check server is returning valid JSON

**Theme not applying:**

- Ensure DuitRegistry.initialize called before runApp
- Verify theme name in JSON matches registered theme
- Check overrideRule if attributes conflict with theme

**Memory leaks:**

- Always dispose XDriver in StatefulWidgets
- Dispose custom transport managers properly

```

### references//environment_vars.md

```markdown
# Environment variables

This page describes compile-time environment variables used across DUIT packages and how to enable/disable them in different workflows.

All variables below are compile-time constants resolved via bool.fromEnvironment, which means they are evaluated at build time and must be provided through the toolchain flags.

## Available variables

1) `duit:throw-on-unspecified-widget-type`

- Package: `flutter_duit`
- Type: `bool` (compile-time)
- Default: `true`
- Purpose: When an unspecified/unknown widget type is encountered, throw `ArgumentError` (when `true`) instead of returning a fallback empty widget (when `false`). Useful during development to surface schema/model issues early.

1) `duit:enable-warm-up`

- Package: `duit_kernel`
- Type: `bool` (compile-time)
- Default: `false`
- Purpose: Enables attribute warm-up routines. When enabled, the kernel may pre-initialize attribute-related structures to reduce first-use latency.

1) `duit:prefer-inline`

- Package: `duit_kernel`
- Type: `bool` (compile-time)
- Default: `true`
- Purpose: Favors inline function strategies in the kernel where supported. Intended for advanced performance tuning and experimentation.

1) `duit:allow-focus-node-override`

- Package: `flutter_duit`
- Type: `bool` (compile-time)
- Default: `false`
- Purpose: Favors inline function strategies in the kernel where supported. Intended for advanced performance tuning and experimentation.
- Назначение: Defines the behavior when binding a `FocusNode` to a driver if an attempt is made to bind a node with the same `nodeId` again.

## How to set

These are compile-time flags and should be passed to the build/test commands.

#### Flutter (run/build/test)

Use `--dart-define` for Flutter CLI commands.

Run the app:

```bash
  flutter run -d macos \
  --dart-define=duit:throw-on-unspecified-widget-type=false \
  --dart-define=duit:enable-warm-up=true \
  --dart-define=duit:prefer-inline=true
```

```

### references/public_api.md

```markdown
# Public Driver API

## Overview

The Public Driver API (`XDriver`) is the public interface for working with the Duit driver. It represents an **extension type wrapper** over the internal `UIDriver`, providing a convenient interface for initializing and managing a Duit application in various operation modes.

### Architecture

```
XDriver (extension type)
    ↓ wraps
UIDriver (internal)
    ↓ uses
DuitDriverCompat (implementation)
```

`XDriver` implements the `FocusCapabilityDelegate` interface to support focus management in the UI.

## Supported Operation Modes

### 1. Remote (Remote Mode)

- Connection to a remote server through the transport layer
- UI is dynamically loaded from the server
- Support for live updates through the transport
- Ideal for backend-driven UI

### 2. Static (Static Mode)

- Working with predefined JSON content without server requests
- Suitable for offline mode, testing, or applications with fixed UI
- Uses `StubTransportManager` by default

### 3. Native Module (Module Mode)

- Integration of Duit as a module into an existing Flutter application
- Uses `NativeTransportManager` by default for communication with the host application
- Allows embedding Duit UI into native applications

## Capability Delegates (Managers)

The driver supports multiple delegates to extend functionality:

| Delegate | Interface | Purpose |
|----------|-----------|---------|
| `transportManager` | `TransportCapabilityDelegate` | Transport layer management (HTTP/WebSocket/Native) |
| `nativeModuleManager` | `NativeModuleCapabilityDelegate` | Platform code invocation |
| `scriptingManager` | `ScriptingCapabilityDelegate` | Client-side script execution |
| `loggingManager` | `LoggingCapabilityDelegate` | Logging customization |
| `focusManager` | `FocusCapabilityDelegate` | UI element focus management |
| `actionManager` | `ServerActionExecutionCapabilityDelegate` | Server action execution |
| `controllerManager` | `UIControllerCapabilityDelegate` | Widget state management |
| `viewManager` | `ViewModelCapabilityDelegate` | View model management |
| `actionParser` | `Parser<ServerAction>` | Parsing server actions from JSON |
| `eventParser` | `Parser<ServerEvent>` | Parsing server events from JSON |

## Public Methods

### Factory Constructors

#### `XDriver.remote()`

Creates a driver for working with a remote Duit server.

**Required parameters:**

- `transportManager` - transport layer manager

**Optional parameters:**

- `initialRequestPayload` - data for the first request to the server
- All capability delegates

#### `XDriver.static()`

Creates a driver for working with static JSON content.

**Required parameters:**

- `content` - JSON structure describing the UI

**Optional parameters:**

- `initialRequestPayload` - initial data for initialization
- `transportManager` - if not specified, uses `StubTransportManager`
- All capability delegates

**Throws:**

- `StateError` if `content` is empty

#### `XDriver.nativeModule()`

Creates a driver for native module mode.

**Optional parameters:**

- `initialRequestPayload` - initial data from the host application
- `transportManager` - if not specified, uses `NativeTransportManager`
- All capability delegates

#### `XDriver.from()` (internal)

Creates an `XDriver` from an existing `UIDriver` instance.
**For internal library use only.** Marked as `@internal`.

### Lifecycle Methods

#### `init()`

Initializes the driver and prepares it for operation.

**Performs:**

- Transport layer initialization
- Loading of initial UI content (for remote mode)
- Setup of all registered delegates and managers
- Event system preparation

**Returns:** `Future<void>` - completes when the driver is fully ready

**Important:** Call only once. Repeated calls may lead to unpredictable behavior.

#### `dispose()`

Releases resources used by the driver.

**Performs:**

- Closes transport connections
- Cancels external event stream subscriptions
- Clears internal caches and state
- Releases resources of all registered managers
- Removes all event handlers

**Important:** After calling `dispose`, the driver becomes unusable. It is recommended to call this in the `dispose` method of the widget using the driver.

### Event Handling Methods

#### `attachExternalHandler()`

Registers an external event handler.

**Parameters:**

- `type` - event handler type (`UserDefinedHandlerKind`)
- `handle` - handler function (`UserDefinedEventHandler`)

**Example:**

```dart
driver.attachExternalHandler(
  UserDefinedHandlerKind.custom('onButtonClick'),
  (eventData) {
    print('Button clicked: ${eventData['id']}');
  },
);
```

Handlers are called synchronously when the corresponding event occurs in the UI. One type can have only one handler; repeated registration replaces the previous one.

#### `addExternalEventStream()`

Adds an external event stream for processing by the driver.

**Parameters:**

- `stream` - event stream in JSON format (`Stream<Map<String, dynamic>>`)

**Example:**

```dart
final websocketStream = WebSocketChannel.connect(
  Uri.parse('ws://example.com'),
).stream.map((data) => jsonDecode(data));

driver.addExternalEventStream(websocketStream);
```

The driver automatically subscribes to the stream when added and unsubscribes when `dispose` is called. Multiple streams can be added; they will be processed in parallel.

**Important:** Ensure that the event structure matches the expected Duit format or is handled by registered external handlers.

### Internal Methods

#### `asInternalDriver`

Provides access to the internal `UIDriver` instance.

**For internal library use only.** Marked as `@internal`. Should not be used in user code. Direct use of `UIDriver` may break encapsulation and lead to unpredictable behavior.

## Usage Examples

### Remote Mode

```dart
final driver = XDriver.remote(
  transportManager: HttpTransportManager(
    baseUrl: 'https://api.example.com',
  ),
  initialRequestPayload: {
    'userId': '12345',
    'theme': 'dark',
  },
  loggingManager: CustomLogger(),
);

await driver.init();
```

### Static Mode

```dart
final uiContent = {
  'type': 'Column',
  'children': [
    {'type': 'Text', 'data': 'Hello World'},
  ],
};

final driver = XDriver.static(uiContent);
await driver.init();
```

### Native Module Mode

```dart
final driver = XDriver.nativeModule(
  nativeModuleManager: MyNativeModuleManager(),
  initialRequestPayload: {
    'hostVersion': '1.0.0',
    'features': ['analytics', 'payments'],
  },
);

await driver.init();
```

### Lifecycle Management

```dart
class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late final XDriver driver;

  @override
  void initState() {
    super.initState();
    driver = XDriver.remote(
      transportManager: myTransport,
    );
    driver.init();
  }

  @override
  void dispose() {
    driver.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => ...;
}
```

## Usage Recommendations

1. **Mode Selection:** Use the mode according to the application architecture:
   - Remote - for backend-driven UI
   - Static - for tests or offline mode
   - NativeModule - for integration into existing applications

2. **Lifecycle:** Always call `init()` before using the driver and `dispose()` when finished.

3. **Capability Delegates:** Connect only necessary delegates to optimize performance.

4. **Error Handling:** Wrap `init()` in try-catch to handle initialization errors.

5. **Single Use:** Do not create multiple driver instances for the same session.

## Design Rationale

Using an **extension type** instead of a regular class allows:

- **Performance:** Extension types do not create additional objects at runtime, reducing overhead
- **Encapsulation:** Hides the internal implementation (`UIDriver`) behind a clean public API
- **Compatibility:** Easily integrates with existing code without type changes
- **Easy Extension:** Ability to add new methods without modifying the base implementation

This decision aligns with modern Dart 3.0+ practices and provides an optimal balance between performance and usability.

```

flutter-duit-bdui | SkillHub