Extensions/ComfyUI-Majoor-OmniCam
ComfyUI Extension

ComfyUI-Majoor-OmniCam

Majoor OmniCam is a camera layout and animation tool for ComfyUI. It lets you prepare camera motion without running image or video generation while editing. You can position cameras, create keyframes, preview motion, and record a simple reference video for compatible video models.

By MajoorWaldi·Created 23 days ago·Updated a day ago· 12
MajoorWaldi/ComfyUI-Majoor-OmniCam
Nodes3
On cloudLocal install
CategoryMajoor/OmniCam
Stars12
Updateda day ago
Readme
<p align="center"> <img src="web/assets/omnicam-icon.png" width="112" alt="Majoor OmniCam"> </p> <h1 align="center">Majoor OmniCam</h1> <p align="center"> <strong>Author camera and object motion in ComfyUI, then compile it for whichever video model you are using.</strong> </p> <p align="center"> <a href="https://github.com/MajoorWaldi/ComfyUI-Majoor-OmniCam"><img src="https://img.shields.io/badge/GitHub-Repo-181717?logo=github" alt="GitHub repo"></a> <a href="https://registry.comfy.org/nodes/majoor-omnicam"><img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.comfy.org%2Fnodes%2Fmajoor-omnicam&query=%24.downloads&label=registry%20installs&color=0b7285" alt="Comfy Registry installs"></a> <a href="https://github.com/MajoorWaldi/ComfyUI-Majoor-OmniCam/releases"><img src="https://img.shields.io/github/downloads/MajoorWaldi/ComfyUI-Majoor-OmniCam/total?label=GitHub%20downloads&style=flat" alt="GitHub release downloads"></a> <a href="https://github.com/MajoorWaldi/ComfyUI-Majoor-OmniCam/stargazers"><img src="https://img.shields.io/github/stars/MajoorWaldi/ComfyUI-Majoor-OmniCam?style=flat" alt="GitHub stars"></a> <a href="https://github.com/MajoorWaldi/ComfyUI-Majoor-OmniCam/issues"><img src="https://img.shields.io/github/issues/MajoorWaldi/ComfyUI-Majoor-OmniCam?style=flat" alt="GitHub issues"></a> </p> <p align="center"> <a href="https://github.com/MajoorWaldi/ComfyUI-Majoor-OmniCam/actions/workflows/test.yml"><img src="https://github.com/MajoorWaldi/ComfyUI-Majoor-OmniCam/actions/workflows/test.yml/badge.svg" alt="CI status"></a> <img src="https://img.shields.io/badge/ComfyUI-0.31%2B-blue" alt="ComfyUI 0.31 or newer"> <img src="https://img.shields.io/badge/Python-3.10--3.13-blue" alt="Python 3.10 to 3.13"> <a href="LICENSE"><img src="https://img.shields.io/github/license/MajoorWaldi/ComfyUI-Majoor-OmniCam?style=flat" alt="MIT License"></a> <img src="https://img.shields.io/badge/Status-experimental-e0a253" alt="Experimental"> <a href="https://ko-fi.com/majoorwaldi"><img src="https://img.shields.io/badge/Ko--fi-Buy_Me_a_White_Monster_Drink-ff5e5b?logo=ko-fi" alt="Support on Ko-fi"></a> </p> <p align="center"> <img src="docs/assets/omnicam-cover.png" width="900" alt="Majoor OmniCam — camera control for generative video: Extract, Direct, Monitor"> </p> <p align="center"> <img src="docs/assets/omnicam-demo.gif" width="760" alt="Authoring a camera move in the OmniCam Director viewport"> </p> <p align="center"><em><a href="docs/assets/omnicam-preview.mp4">▶ Full walkthrough (MP4)</a></em></p>

Video models do not agree on how to be told about motion. One wants camera extrinsics, another wants 2D trajectories, a third wants a reference video and a prompt. OmniCam separates the two halves of that problem: you describe the motion once, and a compiler translates it per model.

Extractor ─┐
           ├─> OMNICAM_MOTION_SCENE ─> Monitor ─> camera embedding
Director ──┘        + playblast                   trajectory JSON / TRACKS
                                                  reference video + prompt

A MotionScene is the canonical model-independent authoring document: cameras, objects, motion layers, cuts and an authoring timeline. Motion layers and cuts use time-based scene semantics; camera and object tracks in v1 still retain authoring-grid information (canvas size, authoring fps, duration) where required, and compile to any model resolution or frame rate. It is what travels between the nodes.

The full OmniCam graph: Load Video, Extractor, Director, Monitor, Save Video

Install

Requires ComfyUI 0.31+ and Python 3.10–3.13. After installing, restart ComfyUI; the nodes appear in the node menu under Majoor › OmniCam.

ComfyUI Manager (recommended)

Open Manager → Custom Nodes Manager, search for Majoor OmniCam, and click Install. This pulls the published Comfy Registry release with its prebuilt frontend bundle.

Manual (git clone)

cd ComfyUI/custom_nodes
git clone https://github.com/MajoorWaldi/ComfyUI-Majoor-OmniCam.git

The built frontend bundle (web/, web-chunks/) is committed, so a plain clone runs as-is — no npm install or build step. There are no required Python packages beyond ComfyUI's own. The Extractor's camera-solver backends (DPVO, pycolmap, OpenCV/SIFT) are all optional and installed separately — see the User Guide.

The three nodes

All three nodes are marked experimental in ComfyUI. Camera authoring and the playblast are stable in practice; the Monitor profile set and the Director Motion Tracks surface may still change before a stable release.

OmniCam Director

OmniCam Director

A small shot-layout tool in a live 3D viewport. Animate cameras and scene references, draw motion layers over the frame, cut between cameras, and record a neutral proxy playblast. This is where a MotionScene is authored.

OmniCam Extractor

OmniCam Extractor

Recover a relative 6DoF camera track from one continuous reference shot and hand it on as a solved MotionScene. Connect it to the Director's solved_scene input to keep editing the recovered move, or take it straight to Monitor.

Solves run outside the prompt queue, so you are not queueing a workflow to see a trajectory. Preview uses native browser video first and falls back to server-decoded frames when a container will not decode in the browser.

OmniCam Monitor

OmniCam Monitor

The model compiler. Pick a target profile; Monitor resolves the timeline, compiles the MotionScene into that model's representation, and runs a preflight that reports what will and will not survive the translation.

Preflight is binding, not decorative: for every named model profile, a downstream node that is missing or whose socket contract has changed blocks the run rather than producing a payload with nowhere to go. external_reference_video is the one exception, by design -- see below.

Profiles

| Profile | Semantic | Monitor output | Connect to | |---|---|---|---| | external_reference_video | reference_video | reference_video + final_prompt | any destination model's own reference-video input | | wan_camera_native | camera_embedding | camera_embedding | WanCameraImageToVideo.camera_conditions | | wan_move_native | screen_tracks | native_tracks | WanMoveTrackToVideo.tracks | | wan_track_native | screen_tracks | tracks_json | WanTrackToVideo.tracks | | wanvideo_ati | screen_tracks | tracks_json | WanVideoATITracks.tracks | | ltx25_motion_track | screen_tracks | tracks_json | LTXVDrawTracks.tracks | | h3_native | reference_video | reference_frames + final_prompt | MiniMaxH3ReferenceToVideo.ref_videos | | h3_api | reference_video | reference_video + final_prompt | MinimaxHailuo03ReferenceNode.reference_video |

external_reference_video is the Monitor default and the odd one out: it names no upstream node, imposes no frame grid or fps conversion, and never blocks on a missing or unrecognized downstream. Use it for a model OmniCam has no named profile for. Every other profile is strict on purpose -- it encodes one real model's contract, and a payload that contract cannot satisfy is a bug worth stopping the queue for.

Switching profile never changes the MotionScene. It does change which Monitor output carries the result, so connect the output this table lists for the profile you selected.

Start here

  1. Add OmniCam Director and compose a shot. Press I at each pose to key it.
  2. Connect motion_scene and playblast_video to OmniCam Monitor.
  3. Choose the profile your downstream model needs, and queue.
  4. Read the preflight, then connect the output named in the table above.

To start from footage instead, put OmniCam Extractor in front and wire its motion_scene output to the Director's solved_scene input.

Complete runnable graphs are in examples/workflows/: each is the official Comfy-Org template for that model with its motion source replaced by OmniCam, so every model, LoRA and sampler setting is upstream's.

What OmniCam will refuse to do

These are preflight results, not bugs:

  • A multi-shot edit on a single-camera profile is blocked. One camera embedding, or one projection basis, cannot describe an edit that cuts to a second camera. Reference-video profiles accept it — the playblast carries the cuts — and drop the single-camera prompt in favour of a neutral one.
  • Trajectories the JSON track formats cannot carry are reported. A layer hidden on the first sample cannot be expressed and is dropped; one that disappears and returns is cut at the gap. Monitor names the affected layers instead of quietly encoding less than you authored.
  • A missing or changed downstream node blocks the run, per profile, so a missing LTX install never blocks a Wan Camera compile.

Documentation

  • Node Guide — inputs, outputs, profiles and workflow contracts.
  • User Guide — authoring, playblasts, extraction, installation.
  • In-app help — contextual help from each node.
  • Shortcuts — viewport, timeline and editing controls.
  • Technical Reference — runtime behaviour, DPVO, validation, development.
  • Security — managed files, upload limits, request boundaries.

License

MIT. See LICENSE.