A desktop studio for AI-orchestrated video production, built with Flutter for macOS and Windows (Linux builds from the same source).
OpenMontage Studio treats video creation as a guided pipeline rather than a blank timeline: an agent proposes a plan, you review and approve each creative stage, and the app composes the result. The interface is studio-first — the preview and a dual-layer timeline take center stage, the agent conversation docks to the side, and every stage ends at an explicit approval gate.
Status: interactive UI prototype. This is the layout and interaction shell with mock data. It does not yet talk to a generation backend, an agent loop, or any provider. See Roadmap.
Productions move through a fixed set of stages, each emitting one artifact that becomes the contract for the next:
idea → script → scene_plan → assets → edit → compose → publish
Creative stages pause for approval; technical stages run through.
The main editor:
┌──────────────────────────────────────────────────────────────┐
│ Top bar project · online/offline · Render · budget meter │
├────┬───────────┬──────────────────────────────┬──────────────┤
│ B │ Side panel │ Preview stage │ Inspector │
│ a │ agent chat │ selected scene + transport │ scene props + │
│ il │ or assets │ │ approval gate │
├────┴───────────┴──────────────────────────────┴──────────────┤
│ Timeline stage track (7 stages) + scene strip + playhead │
├──────────────────────────────────────────────────────────────┤
│ Capability bar "X of Y configured" per family · runtime │
└──────────────────────────────────────────────────────────────┘
Wired into the core see → tweak → approve → advance loop:
- Click a scene block in the timeline → the preview jumps to it and the inspector loads its editable properties.
- Scrub the transport → the selected scene follows the playhead.
- The side panel hosts the agent conversation (with an openable artifact card) and the asset galleries; the rail toggles between them and collapses the panel.
- Approve & continue is the stage checkpoint gate.
- The top bar toggles online/offline; the footer shows the capability rollup
with a
💻marker on families that work offline.
Dark slate base with a single bright accent:
| Token | Value | Use |
|---|---|---|
| Background | #0F172A |
App base |
| Surface | #1E293B |
Panels |
| Accent (cyan) | #22D3EE |
Active state, primary action |
| Accent (purple) | #A78BFA |
Agent, secondary |
| Approve (green) | #34D399 |
Checkpoint gate, "done" status |
| Awaiting (amber) | #F59E0B |
Stage awaiting approval |
See lib/theme/app_theme.dart.
lib/
├── main.dart App entry + MaterialApp theme
├── theme/app_theme.dart Color tokens + dark theme
├── models/studio_models.dart Stage/Scene/Capability/Chat/Asset models + fixtures
├── screens/ One file per top-level screen
└── widgets/ Region widgets (top bar, rail, preview, inspector, …)
Requires the Flutter SDK with
macOS desktop support enabled (flutter config --enable-macos-desktop).
flutter pub get
flutter run -d macos # launch the app
flutter test # widget tests
flutter analyze # static analysisThe agent chat in the studio is wired to a real local LLM via
Ollama — no API key, fully offline. This is the first
real backend connection: OllamaClient talks to http://localhost:11434,
which is the "localhost provider" boundary the rest of the engine will follow.
To use it:
# one-time: install Ollama and pull a model
brew install ollama
ollama serve # starts the local server on :11434
ollama pull qwen2.5 # ~4.7 GB
# verify the app's client can reach it
dart run tool/agent_smoke.dartWith Ollama running, the chat header shows the connected model (e.g.
qwen2.5:latest) and messages get real replies. If Ollama is down, the chat
degrades gracefully and the header shows agent offline. The macOS sandbox
needs the com.apple.security.network.client entitlement (already set) to reach
localhost.
Beyond chat, the agent also produces structured output: typing a brief on the
home screen and pressing Create asks the local model for a JSON scene plan
(AgentService.planScenes), which is parsed into scenes that drive the studio's
timeline, preview, and inspector. If the model is unreachable or the response
isn't usable, the studio opens with the sample plan instead.
The agent's behavior is driven by editable markdown skills, not hard-coded
prompts: a production overview plus one director skill per pipeline stage
(idea → … → compose). AgentService loads them at runtime (falling back to
embedded text if assets are unavailable), so you change how the agent works by
editing the skills — the Dart code is just plumbing. All skill content is
original to this project.
The app drives the local toolchain in-process from Dart (no sidecar server), giving real narration and real video, offline, no API key.
- Narration runs through a pluggable
VoiceSource: the OS-native engine (macOSsay, Windows SAPI via PowerShell, Linuxespeak-ng) is free and offline and is the default, with ElevenLabs cloud neural voices as an opt-in upgrade. The source is chosen in Settings; the renderer synthesizes each scene through whichever is active. - Render composites the whole scene plan into a real MP4 via ffmpeg
(fast designed cards with cross-fades) or Remotion (
npx remotion render, cinematic motion graphics) — animated kickers, headlines, stat reveals, and real bar/pie charts, each with its narration, concatenated. A 1920×1080 H.264 + AAC file on disk, produced entirely locally.
TtsClient, RenderClient, VoiceSettings, and MediaSettings are the Dart
sides; the CommandRunner seam injects an OS-appropriate PATH and is swapped for
a fake in tests, so the media clients run without spawning real processes.
- Agent tool-calling — extend structured output from scene plans to the rest of the pipeline (edit decisions, asset prompts), with the approval gates feeding results back to the agent. (Started: brief → scene_plan.)
- Engine bridge — reach cloud and local generators uniformly over
localhostendpoints, so online/offline is just "which endpoint." (Started: Ollama, TTS, render.) - Richer render — per-scene images/clips and motion instead of color cards.
- Packaging — bundle the render toolchain, download models on demand.
Package a build:
scripts/package_macos.sh # -> dist/OpenMontageStudio-<version>.dmgThis produces a drag-to-install .dmg. It is not signed — for a release
users can open without a Gatekeeper warning you need an Apple Developer ID:
codesign --deep --force --options runtime \
--sign "Developer ID Application: <NAME> (<TEAMID>)" <app>
xcrun notarytool submit <dmg> --apple-id <id> --team-id <TEAMID> \
--password <app-specific-password> --wait
xcrun stapler staple <dmg>Hosting: the site (Cloudflare Pages) serves the installer at
get.opencli.ai/download/OpenMontageStudio.dmg and a version manifest at
get.opencli.ai/version.json.
In-app updates: on launch the home screen fetches version.json
(UpdateChecker) and shows a "Version X is available · Download" banner when a
newer release exists. To ship an update: build + sign the new .dmg, upload it,
and bump both pubspec.yaml version:/lib/app_version.dart and version.json.
For true one-click auto-install (download + relaunch), the next step is
Sparkle via the auto_updater plugin with a
signed appcast.
MIT © AI Dashboard.