Open-source 3D flight planner for drone cinematography, built on CesiumJS.
Plan a shot on a 3D globe, aim the camera exactly, see what the drone will see,
render a previz video, and export the mission to your drone.
Features · Tour · Organizing a flight · Projects & recovery · Getting started · Shortcuts · Export formats · Architecture · Contributing
Warning
Early development. OpenDroneCinematic plans flights for real aircraft. Test every exported mission in a safe, open area with plenty of height before you fly it near people or obstacles, and always follow your local airspace rules.
| Feature | What it does |
|---|---|
| 🗂️ Projects and recovery | A project home with recent files, portable .odc.json projects, Save / Save as, local recovery drafts and unsaved-change protection. |
| 🧭 Flight organization | Named waypoints and groups, drag-and-drop ordering, searchable filters, visible bulk actions, and an outline designed for large surveys. |
| 🌍 Plan on a real 3D globe | Cesium World Terrain, aerial imagery, OSM Buildings, Google Photorealistic 3D Tiles, or your own photogrammetry. |
| 🎯 Aim the camera exactly | Points of interest, heading and gimbal modes per waypoint, smooth easing between them. |
| 🎥 See what the drone sees | A live camera view using the drone's real field of view. Swap it with the map at any time. |
| ☀️ Sun and golden hour | Real sun lighting and shadows for the shoot date and time, golden and blue hour on a day strip, and the light on your shot. |
| 🔭 Zoom and dolly zoom | Per-waypoint focal length with real lens data, lens-switch and digital-zoom marks, a vertigo template and framing guides. |
| 🕹️ Fly mode | Fly a simulated drone with keyboard, mouse or gamepad. Drop waypoints, mark POIs, or record a flight path. |
| 🎬 Shot templates | Orbit, helix, reveal, dolly, fly-by and dronie, generated around a subject in one click. |
| 🗺️ Survey grids | Draw an area, set height and overlap, get a lawnmower grid with GSD, photo count and distance-triggered photos. |
| 🛡️ Safety checks | Terrain and building clearance, 120 m ceiling, range, speed, climb rate and battery. |
| 🗺️ Airspace overlays | Download OpenAIP country airspaces or import GeoJSON footprints, with route-crossing warnings and explicit source/freshness limits. No live regulatory feed. |
| 📤 Export to your drone | Litchi CSV, DJI WPML/KMZ, QGroundControl .plan and Mission Planner, with an option to match the preview. |
| 📥 Import missions | Open Litchi CSV, DJI KMZ, QGC .plan and Mission Planner files to preview, edit and re-export them. |
| ⛰️ GeoTIFF terrain | Load your own elevation model (SRTM, Copernicus, lidar) for offline terrain, safety checks and terrain following. |
| 🎞️ Render previz video | Frame-exact MP4, WebM or GIF at up to 4K. Compare takes side by side with the live view. |
The screenshots below are captured from the current browser app with demonstration projects. Map views use OpenStreetMap on flat terrain, without an API token; these examples are not flight-ready missions.
The app opens on Projects, with New project, Open project, your recent projects, and a practice mission. Unsaved work from the previous session appears as a recovery draft instead of silently opening in the planner. The practice mission uses illustrative terrain heights and is not flight-ready.
In the planner, the Flight outline organizes waypoints and POIs on the left. The right-hand Inspector provides Details, Mission, Create, Light, and Safety tabs. The project header shows whether changes are saved to a file and whether a local recovery copy is available. Save (Ctrl+S) updates the current desktop file; Save as… (Ctrl+Shift+S) creates a separate copy. Creating/opening another project or closing the desktop app asks you to save, discard, or cancel when there are unsaved changes.
See recovery drafts and unsaved-change protection
An unsaved local draft appears above recent projects after restarting. Recover opens it for review without silently overwriting the saved project file.
Switching away from an edited project offers Save changes, Discard changes, or Cancel.
Recovery is a best-effort local backup, not a substitute for saving a .odc.json file. In the browser, saving downloads a file and recent projects reopen the last saved browser snapshot; use Open project to read the latest file from disk. See Projects and recovery for details.
Click Waypoint (W) and then click the globe to add waypoints, or click POI (P) to mark what the camera should look at. Drag any waypoint, POI or the takeoff point (T) to move it. The flight path is a smooth spline through your waypoints. Dashed stems make heights readable in 3D; dense missions show stems for the active waypoint and small selections to keep the map clear.
Name waypoints in Details, check several to edit together, and click Group to organize shots or survey blocks. Drag a waypoint or group handle to change flight order, or use Move up / down. Search and filter the outline, then Locate a selection on the map or Preview its camera view. Large missions use a virtualized outline and simplified map/timeline labels. See Organizing a flight for selection behavior, grouping, and keyboard shortcuts.
Use Undo/Redo (Ctrl+Z / Ctrl+Y) freely within a project. Edits update a local recovery draft; Save / Open store and load portable .odc.json files. Opening a different project starts a fresh undo history.
- Name and group: organize one continuous flight into sections such as Approach, Orbit, and Reveal. Drag a waypoint or a whole group to change the flight order.
- Select and edit: use checkboxes, Ctrl/⌘-click, or Shift-click. The inspector shows shared values and marks differing values as Mixed. Group, duplicate, move, and delete are always available in the outline footer.
- Find and focus: search names, groups, tracked subjects, or actions; filter by a specific group. The footer makes selections outside the filter explicit. Collapse either side panel when you want more room for the map.
See a 2,000-waypoint survey in the new workspace
The outline renders only visible rows, timeline markers adapt to the available width, and the map labels the active waypoint instead of drawing thousands of overlapping badges. Here, a group filter isolates 100 waypoints for bulk editing.
Names and groups are saved with the project. Grouping preserves flight order; exports use the actual waypoint sequence. See Organizing a flight for drag-and-drop behavior, filtered selections, and shortcuts.
Every waypoint picks how the aircraft turns and how the gimbal tilts. The app blends between neighbouring waypoints with an ease-in/ease-out curve, so the camera never snaps.
| Heading | What it does |
|---|---|
| Along path | The nose follows the direction of travel. |
| Face POI | The aircraft turns to keep the point of interest centred, all along the leg. |
| Fixed | Holds a compass heading you set. |
| Gimbal | What it does |
|---|---|
| Fixed pitch | Holds a tilt angle, for example −20°. |
| Track POI | Tilts continuously to keep the POI's aim height in frame. |
The POI tracking is computed for every frame of the flight, not only at the waypoints. Gimbal limits come from the drone profile.
The camera view renders exactly what the drone camera will record. It uses the profile's horizontal field of view (72° for a 24 mm-equivalent lens), the video's 16:9 frame, and a rule-of-thirds overlay. The HUD shows heading, gimbal, speed, altitude, height above ground, distance from home, FOV and the sun (its height, and whether the shot is backlit, front-lit or side-lit, or the sun is in frame).
- With the map canvas focused, press Tab, click the mini-screen, or use Camera view / Map view to swap the main screen and the mini-screen.
- Drag the mini-screen's top bar to move it, and its top-left corner to resize it. The layout is remembered.
- Press L or Mini-screen / Split to show the map and camera side by side. ⬌ / ⬍ stacks them instead; drag the divider to resize, double-click it to centre.
- The map zoom control (1× by default) sets mouse-wheel zoom speed (slow, normal, fast or anything between), and Snappy stops the zoom as soon as the wheel stops.
- Press Space or ▶ to play the flight, and scrub the timeline. The numbered ticks on the timeline jump to each waypoint.
Each waypoint has a Zoom (35mm-equivalent focal length). The zoom eases between waypoints, and the camera view, map frustum and renders all follow it. Drones with several cameras (Air 3/3S, Mavic 3 Pro, Mavic 4 Pro) have lens presets. Other drones get 2× digital zoom.
- The HUD shows the focal length, and DIGITAL n× when the real drone would be zooming digitally on one of its cameras.
- Orange marks on the timeline show where the drone would switch cameras, which shows as a jump in real footage. Thin marks show where digital zoom starts.
- Keep subject size (dolly zoom) on a waypoint zooms on the way there so the POI stays the same size as at the last waypoint without it.
- The Dolly zoom (vertigo) shot template builds the move for you: pull out while zooming in, or push in while zooming out, up to the drone's zoom range.
- ▦ Guides in the camera view adds 2.39:1 / 1.85:1 letterbox masks, 9:16 / 4:5 crop outlines, action- and title-safe frames with a centre cross, and the true horizon. Guides never appear in renders.
Zoom is preview-only: exported missions fly on the main camera, and the export dialog says so.
The Light panel sets the shoot date, takeoff time and the location's UTC offset, saved with the mission (a new mission starts at today's evening golden hour). The map, the camera view and rendered video are lit by the real sun for that moment, and the sun moves as the timeline plays. The camera view and renders also draw shadows from terrain, buildings and 3D tiles; turn them off in the panel on slower machines.
- The day strip shows night, blue hour, golden hour and daylight; click it to set the takeoff time. The white mark is takeoff, the yellow mark the timeline cursor.
- 🌅, 🌇 and 🌆 jump to the morning golden hour, evening golden hour and blue hour (hover for their times).
- For each golden hour the panel says how the light falls on the shot, from the way the camera mostly faces: front-lit, backlit or side light.
Golden hour is when the sun is between 4° below and 6° above the horizon; blue hour from 6° to 4° below.
Press F (or Fly) to take control of a virtual drone from the camera view, and scout the shot the way you'd fly it. It behaves like a drone in normal mode: it uses the profile's speed and climb limits, accelerates and brakes smoothly, hovers when you let go, and won't fly into terrain or buildings. The mini-map switches to a chase view behind the drone.
| Action | Keyboard / mouse | Gamepad (Mode 2) |
|---|---|---|
| Fly forward / back / sideways | W S A D |
Right stick |
| Climb / descend | R / F |
Left stick ↕ |
| Yaw | Q / E or drag |
Left stick ↔ |
| Tilt gimbal | ↑ / ↓ or mouse wheel |
LT / RT |
| Sport speed | hold Shift |
hold RB |
| Drop a waypoint at the current position, height, heading and tilt | Space |
A |
| Mark a POI where the crosshair hits terrain or buildings | P |
B |
| Record the flight path (press again to stop) | L |
X |
| Exit fly mode | Esc |
A recorded path is simplified into waypoints that keep your position, camera yaw and gimbal tilt within a couple of metres or degrees. Each leg keeps the speed you flew, and the spots where you paused become hovers.
Open Create → Survey, click Draw area (or press G) and click the corners of the area on the globe. Drag the green corners to adjust; undo removes the last one. Then set:
- Height (AGL): sets the ground sample distance (GSD), shown live in cm/px for the selected drone's camera
- Front / side overlap: the spacing between photos along a line and between lines (75% / 65% by default)
- Line angle: or click Auto to run lines along the longest edge for the fewest turns
- Overshoot: extends lines past the outline so the edges are fully covered
- Terrain follow: adds a waypoint every N metres along each line at the survey height above the ground, for hilly sites
- Crosshatch: flies a second grid at 90° for 3D reconstruction
Generate waypoints builds a serpentine of nadir lines with a fixed heading. Each line starts photos every N metres at its first waypoint and stops them at its last, so the turns take no photos. The panel shows the area, GSD, line count, photo spacing and an estimated photo count, and warns when the photo interval is too fast for the camera.
The generated grid arrives in a named Survey grid group. Select portions in the outline to organize them into additional named blocks and edit their shared settings.
Distance-triggered photos export as Litchi photo_distinterval, DJI WPML multipleDistance action groups and MAVLink DO_SET_CAM_TRIGG_DIST.
Note
Clearance checks need real terrain, so add a free Cesium ion token (see Map data). Safety → Airspace overlays can download OpenAIP country airspaces in the desktop app or import local GeoJSON for horizontal footprint warnings. No authoritative coverage or live NOTAM feed is included; altitude limits and activation are not evaluated. Always check official sources. See Airspace overlays.
![]() |
Open… also imports all four formats, so you can preview, check and convert missions made in other apps. See docs/exports.md for the full mapping and known limits. |
While it renders, a REC overlay shows the frame count, file size, time remaining and any frames where tiles were slow to load. You can cancel at any time.
Every render becomes a take that plays right inside the camera view. Open 🎞 Takes to replay, save or delete a take, or click ⇆ Compare to play it side by side with the live 3D view. Both sides follow the timeline, so you can change the plan and see the difference straight away.
47 profiles, grouped by app in the Drone picker. Each sets the camera (field of view and ground sample distance), speed and climb limits, flight time and gimbal range.
| Group | Models | Exports |
|---|---|---|
| DJI consumer (DJI Fly) | Mini 2 / SE, Mini 3, Mini 3 Pro, Mini 4 Pro, Mini 5 Pro, Air 2, Air 2S, Air 3, Air 3S, Mavic 3 / Classic / Cine, Mavic 3 Pro, Mavic 4 Pro | Litchi¹, DJI KMZ² |
| DJI consumer, previz only | Mini 4K / Mini 2 SE, Lito 1, Lito X1, Flip, Neo, Avata 2 | none (no waypoint API) |
| DJI enterprise (DJI Pilot 2) | Mavic 3E / 3T / 3M, Matrice 3D / 3TD, Matrice 4E / 4T / 4D / 4TD, Matrice 30 / 30T, Matrice 300 RTK (H20, P1), Matrice 350 RTK (H20, H30, P1, L2) | DJI KMZ³ |
| DJI enterprise, other apps | Inspire 3, Phantom 4 RTK | none |
| DJI older (DJI GO 4) | Mavic 2 Pro, Mavic 2 Zoom, Mavic Pro, Mavic Air, Spark, Phantom 4 / Advanced, Phantom 4 Pro / V2.0, Inspire 2 + X5S | Litchi |
| Open autopilots | ArduPilot / PX4 multirotor | QGC .plan, Mission Planner |
| Custom | your own lens, speed and battery | all |
¹ Only for drones Litchi supports. ² DJI Fly has no KMZ import: replace a mission it created (see docs/exports.md). The Mini 4 Pro enum value is community-sourced; other DJI Fly drones fall back to a generic one, with a warning. ³ Enum values for the M300, M350, M30, Mavic 3 enterprise and Matrice 3D series match DJI's Cloud API. Matrice 4, H30 and L2 values are not yet confirmed and the export says so. Specs for the Lito 1 and Lito X1 come from early reviews. Please help verify.
The screenshots use OpenStreetMap with terrain disabled. Choose imagery, terrain, and buildings in Map data. For Cesium World Terrain, aerial imagery, and OSM 3D buildings:
- Create a free account at ion.cesium.com.
- Copy your default access token.
- Paste it in Map data. The token is stored only on your computer.
To work offline or with better local data, pick Terrain → GeoTIFF DEM (local) and load a single-band elevation GeoTIFF in WGS84 (EPSG:4326), Web Mercator or UTM. Most DEMs are heights above sea level, so set Height offset to the local geoid height (about +48 m in central Europe) to get WGS84 heights. Reproject other coordinate systems first, for example with gdalwarp -t_srs EPSG:4326 in.tif out.tif.
Under Your own 3D Tiles you can add photogrammetry or scans exported as 3D Tiles. In the browser, give a URL. In the desktop app, you can also browse to a local folder.
Google Photorealistic and Cesium ion binary tile payloads are automatically cached in the app's private IndexedDB storage, up to 10 GB of payload data (or less if the browser/webview quota is smaller). Map data → Tile cache shows usage and lets you clear it. Least recently used tiles are evicted first; clearing this cache does not remove missions, downloaded countries or GeoTIFF DEMs.
Tiles are saved byte-for-byte at the detail level actually requested. Fine and coarse tiles have separate keys, so a coarse tile cannot replace a fine one. This does not force or prefetch maximum detail: Cesium still chooses the appropriate level for the current view. Sessions, tokens and request headers remain part of the cache identity; changing them may require fresh downloads.
Only successful full binary responses with explicit, readable HTTP freshness information are saved. no-store, no-cache, Vary: *, expiry and response age are respected; stale tiles go through Cesium's normal XHR/browser HTTP-cache path, including normal browser revalidation where available. If freshness headers are hidden by CORS, caching is skipped. This is not an unrestricted offline Google Maps archive, and an ion token does not override the provider's terms. Manifest JSON, image-element requests and other providers continue using normal browser caching. Storage failures fall back to normal loading, and clearing app/browser data removes the cache.
Installers for Windows (.exe, .msi), macOS (.dmg) and Linux (.AppImage, .deb) are attached to each GitHub Release. The Release workflow builds them whenever a v* tag is pushed. Installers are not signed by a trusted publisher; Windows SmartScreen, macOS Gatekeeper or organizational policy may warn or block installation.
M3 adds Map data → Updates for configured, signature-verified desktop builds. Only a free updater key pair is needed—Windows publisher certificates and Apple notarization are not required or configured. macOS bundles use ad-hoc signing; OS trust warnings may remain. Unconfigured builds use manual installers. See Updater setup.
You need Node.js 22+. For the desktop app you also need Rust and the Tauri prerequisites.
npm installRun in the browser, the fastest way to try it:
npm run devThen open http://localhost:1420.
Run it as a desktop app:
npm run tauri devBuild installers for your OS:
npm run tauri build| Key | Action | Key | Action |
|---|---|---|---|
V |
Select tool | Space |
Play / pause |
W |
Add waypoints | Tab |
Swap camera / map |
P |
Add POI | F |
Fly mode |
T |
Set takeoff | Del |
Delete selected |
G |
Draw survey | L |
Split / mini-screen |
Esc |
Cancel / exit | Ctrl+Z / Ctrl+Y |
Undo / redo |
Ctrl+N |
New project | Ctrl+O |
Open project / import |
Ctrl+S |
Save project | Ctrl+Shift+S |
Save project as… |
With focus in the flight outline, use ↑ / ↓ and Home / End to navigate, Ctrl+A to select matching waypoints, Ctrl+D to duplicate, and Alt+↑ / Alt+↓ to reorder. Hold Shift to extend selection. On macOS, use ⌘ for Ctrl shortcuts; ⌘+Shift+Z redoes an edit.
apps/desktop/ Tauri 2 + React app (src/ is the UI, src-tauri/ is the Rust shell)
packages/core/ Pure TypeScript: geodesy, mission model, spline path and timing,
camera maths, drone profiles, safety, shot templates, flight sim,
survey grids, DEM sampling and UTM maths
packages/exporters/ Litchi CSV, DJI WPML/KMZ, QGC .plan and Mission Planner writers and
importers, with golden-file and round-trip tests
packages/cesium-view/ CesiumJS: data sources, mission rendering, picking, ground sampling,
camera view and the offline frame renderer
docs/ Architecture, export notes, logo and screenshots
core and exporters never import Cesium, so they run and test in plain Node. The design is explained in docs/architecture.md.
npm test # unit and golden-file tests (Vitest)
npm run typecheck # TypeScript across all packages
npm run format # PrettierIf you change an exporter on purpose, update its golden files with npx vitest run -u and review the diff.
- M1: cinematic planning. Waypoints, POIs, camera preview, templates, safety, Litchi and DJI export, fly mode, video renders
- M2: mapping and more drones. Survey grids (polygon, overlap, GSD), QGroundControl
.plan/ MAVLink export, GeoTIFF terrain, importing KMZ, Litchi and.planfiles - M3: polish (in progress). Local airspace overlays, signature-verified updates (without paid OS signing), and an exporter plugin API. See M3 status and remaining release gates.
Contributions are very welcome! Especially wanted:
- Verified DJI enum values for consumer drones
- Real-world flight test reports
- New drone profiles
- New exporters
See CONTRIBUTING.md.
MIT © OpenDroneCinematic contributors.
CesiumJS is Apache-2.0. Map data comes from its providers under their own terms. Screenshot map data © OpenStreetMap contributors.














