Web · Flutter

Embed the editor
in any Flutter Web app.

Lumen mounts directly into a Flutter Web canvas via HtmlElementView and a typed JS interop bridge — your users get the full editor, no iframe gymnastics.

60fps
Skia / WASM
JS interop
Typed events
PWA-ready
Service worker
app.acme.health/decks/series-bflutter web · canvaskit
Acme Health · Pitch deckFlutter 3.24 Lumen mounted
Lumen
The future of pitch decks
Generated with Lumen AI
ARR · 2026
$48M
+312% YoY · 12,400 customers
M1
12M
M2
28M
M3
48M
Revenue Growth
Q1 2024 — Q4 2026
Product · v3
A new way to build slides
"Lumen replaced our entire deck workflow."
Sara Chen · Head of Brand, Linear
ARR · 2026
$48M
+312% YoY · 12,400 customers
M1
12M
M2
28M
M3
48M
AI: Make this confident, lead with the $48M ARR…
Layout
Typography
Inter · 600 · 56
Color
Effects
SDK Architecture
L1
Flutter Web App
Your routes, widgets, state · compiled to dart2js / WASM
L2
HtmlElementView ↔ JS interop
Typed event channel · Dart ↔ JS · zero iframe
L3
Lumen SDK (web)
Editor + canvas + scene graph engine in the same DOM
L4
Host APIs
Templates · AI · Data · Image · Storage
Dart · DeckScreen.dart
flutter web
// pubspec.yaml: lumen_flutter_web: ^3.0.0

import 'package:flutter/material.dart';
import 'package:lumen_flutter_web/lumen_flutter_web.dart';

class DeckScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Pitch deck')),
      body: LumenEditorView( // HtmlElementView under the hood
        apiKey: env.lumenKey,
        deckId: 'acme-series-b',
        template: 'investor.v3',
        data: {
          'company': 'Acme Health',
          'arr': '\$48M',
          'fda': true,
        },
        onEvent: (event) {
          if (event.type == 'export.done') {
            html.window.open(event.payload['url'], '_blank');
          }
        },
      ),
    );
  }
}
Event bridge · live
JS interop stream from Lumen → Flutter Web
connected
12:04:18editor.readyscene graph hydrated
12:04:22slide.select{ id: 's3' }
12:04:24ai.generate{ node: 'b3f4', mode: 'text' }
12:04:26ai.complete4 variations · 1.8s
12:04:31node.update{ id: 'b3f4', value: '$48M ARR' }
12:04:48export.start{ format: 'pdf' }
12:04:50export.doneurl: cdn.lumen.app/.../v3.pdf
Documentation

Integrate the Lumen SDK into Flutter Web

Five steps from pubspec.yaml to a fully embedded editor — wired to your own templates, AI, data, image, and storage providers.

1
Install
Add the Dart wrapper and load the Lumen runtime in web/index.html.
pubspec.yaml
yaml
# pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  lumen_flutter_web: ^3.0.0  # Dart wrapper around the Lumen JS SDK
web/index.html
html
<!-- web/index.html — load the Lumen runtime before main.dart.js -->
<script src="https://cdn.lumen.app/sdk/v3/lumen.min.js"
        data-api-key="pk_live_xxx"></script>
2
Initialize
Boot the SDK once, before runApp(). Theme follows MediaQuery.
lib/main.dart
dart
// main.dart — register the platform view once at startup
import 'package:lumen_flutter_web/lumen_flutter_web.dart';

void main() {
  LumenSdk.init(
    apiKey: const String.fromEnvironment('LUMEN_KEY'),
    workspace: 'acme-health',
    theme: LumenTheme.auto, // syncs with MediaQuery brightness
  );
  runApp(const MyApp());
}
3
Embed
Drop LumenEditorView anywhere — it's a real Flutter widget.
DeckScreen.dart
dart
// Anywhere in your widget tree
LumenEditorView(
  deckId: 'acme-series-b',
  template: 'investor.v3',
  host: myHostConfig,        // your TemplateProvider, AiProvider, ...
  initialData: {'company': 'Acme Health', 'arr': r'$48M'},
  onEvent: (LumenEvent e) {
    switch (e.type) {
      case LumenEventType.exportDone:
        html.window.open(e.payload['url'] as String, '_blank');
        break;
      case LumenEventType.error:
        showSnack(e.payload['message'] as String);
        break;
      default:
        break;
    }
  },
)
4
Implement the host interfaces
The SDK is bring-your-own-backend. Implement the 5 providers and pass them via LumenHostConfig.
TemplateProvider

Resolve template HTML + scene-graph schema by id.

AiProvider

Stream text completions and synthesize images.

DataProvider

Resolve `{{bindings}}` from CRMs, Postgres, REST.

ImageProvider

Upload, search stock, return CDN-friendly URIs.

StorageProvider

Load and save serialized DeckSnapshot blobs.

lib/lumen/interfaces.dart
dart
// lib/lumen/interfaces.dart — the contract host apps implement

abstract class TemplateProvider {
  Future<List<TemplateMeta>> list({String? query});
  Future<TemplateDoc> get(String id);
}

abstract class AiProvider {
  Stream<AiChunk> generateText(AiTextRequest req);
  Future<AiImage> generateImage(AiImageRequest req);
}

abstract class DataProvider {
  Future<Map<String, dynamic>> resolve(String binding, {Map<String, dynamic>? ctx});
}

abstract class ImageProvider {
  Future<Uri> upload(Uint8List bytes, {required String mime});
  Future<List<StockImage>> search(String query);
}

abstract class StorageProvider {
  Future<DeckSnapshot?> load(String deckId);
  Future<void> save(String deckId, DeckSnapshot snap);
}

class LumenHostConfig {
  final TemplateProvider templates;
  final AiProvider ai;
  final DataProvider data;
  final ImageProvider images;
  final StorageProvider storage;
  const LumenHostConfig({
    required this.templates,
    required this.ai,
    required this.data,
    required this.images,
    required this.storage,
  });
}
5
Listen to editor events
Every meaningful action in the editor is emitted on the JS interop bridge as a typed LumenEvent.
EventPayloadWhat to do
editor.ready{ deckId, slideCount }Hide your loader, enable toolbar.
slide.select{ id, index }Sync your outline / sidebar.
node.update{ id, path, value }Persist incrementally to your DB.
ai.generate{ node, mode, prompt }Show usage / spinner in host UI.
ai.complete{ node, variations[] }Log analytics, charge credits.
export.start{ format }Disable share button until done.
export.done{ format, url, bytes }Open / share / store the file.
error{ code, message }Toast and report to Sentry.
Two-way binding

Dispatch LumenSdk.update(nodeId, value) from Dart to push host state into the canvas.

Auth

Provide a signed JWT via TemplateProvider — Lumen never sees your end-user credentials.

Tree-shaking

Only the providers you wire are bundled. Unused engines (charts, video) lazy-load on demand.