Skip to content

Commit 7f80065

Browse files
Remove unfinished collaboration system and introduce detailed, consistent tooltips across the UI - and made codebase more explorable by making it modular - and updated documentation as well
1 parent 71120cc commit 7f80065

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+11552
-23012
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ __pycache__/
44
local/
55
*.pyc
66
*.zip
7+
*.rar

README.md

Lines changed: 22 additions & 203 deletions
Original file line numberDiff line numberDiff line change
@@ -1,203 +1,22 @@
1-
# 🌿 EfficientManim — The Ultimate Node-Based Manim IDE
2-
3-
![Icon](icon/icon.ico)
4-
5-
[![IdeaCred](https://ideacred.com/api/badge/pro-grammer-SD/EfficientManim?style=for-the-badge)](https://ideacred.com/submissions)
6-
7-
**🌈 Create mathematical animations visually with the power of Python, AI, and real-time collaboration.**
8-
9-
---
10-
11-
## 🚀 Key Features
12-
13-
### 🎬 Node-Based Visual Workflow
14-
- **Visual Editor:** Drag-and-drop Mobjects and Animations with intuitive wiring
15-
- **Infinite Canvas:** Pan and zoom freely to manage large node graphs
16-
- **Live Preview:** Real-time static previews of individual nodes
17-
- **Smart Connections:** Automatic wire validation and scene synchronization
18-
19-
### 🎬 Multiple Scenes
20-
- Manage multiple scenes per project in the **Scenes** tab
21-
- Create, rename, delete, and switch between scenes — each with its own node graph
22-
- Scene state auto-saved and restored when switching
23-
24-
### 📦 VGroup Utility
25-
- Select Mobject nodes → click **Create VGroup** in the **VGroups** tab
26-
- VGroup code automatically generated: `group_1 = VGroup(circle_1, square_1)`
27-
- Groups shown in expandable tree view with source badges (canvas / AI / snippet / GitHub)
28-
- Full member management: add, remove, highlight on canvas, copy code
29-
30-
---
31-
32-
## 🤝 Live Collaboration
33-
34-
EfficientManim supports **real-time multi-user editing** over a local network or on the same machine — no cloud accounts, no third-party services.
35-
36-
### What It Is
37-
Two or more EfficientManim windows share the same node graph live. Every node move, property change, wire add/delete, and scene switch is broadcast as a JSON delta and applied to all connected instances within milliseconds. A 6-digit **PIN** identifies the session — easy to read aloud or paste into chat.
38-
39-
### Starting a Session
40-
1. Open your project in EfficientManim.
41-
2. Click **Collaboration → Start Live Collaboration**.
42-
3. A dialog shows your PIN in large, bold text. Share it with collaborators.
43-
4. The toolbar shows a green ● and the active PIN.
44-
45-
### Joining a Session
46-
1. Click **Collaboration → Join Collaboration**.
47-
2. Enter the 6-digit PIN.
48-
3. Click **Connect** — your canvas loads the host's full graph and live sync begins.
49-
50-
### Multi-Window (Same Machine)
51-
Run `python main.py` a second time, join via the same PIN — both windows stay in sync.
52-
53-
### Network Requirements
54-
- **Same machine:** No setup needed.
55-
- **LAN:** Host firewall must allow the ephemeral TCP port shown in the session dialog.
56-
- **Internet:** Not supported out-of-the-box; use a reverse proxy (e.g. `ngrok`) on the host.
57-
58-
📖 Full details: [docs/live_collaboration.md](docs/live_collaboration.md)
59-
60-
---
61-
62-
## 🤖 Gemini AI Integration
63-
64-
### Code Generation
65-
- Describe animations in plain English — AI generates a complete `Scene.construct()` block
66-
- AI code parsed into typed, editable nodes with correct wiring
67-
- Streaming responses with real-time feedback in the AI Assistant dock
68-
69-
### MCP Agent Mode
70-
- Gemini reads the live scene state as JSON and issues typed commands executed directly against the running app
71-
- No merge step — Gemini edits the graph the same way a human would
72-
- Full action log: **Help → MCP Agent → Show Action Log**
73-
74-
### Auto Voiceover Agent
75-
- Analyzes all nodes, writes per-node scripts, generates TTS, attaches audio automatically
76-
- At render time, all segments merge into a synchronized voiceover track
77-
78-
📖 Full details: [docs/ai_features.md](docs/ai_features.md)
79-
80-
---
81-
82-
## 🎙️ AI Voiceover Studio
83-
- Gemini TTS with six voices: Puck, Charon, Kore, Fenrir, Aoede, Zephyr
84-
- Built-in audio player with play/pause/stop/seek and time display
85-
- Attach audio to any node — duration auto-syncs `run_time=`
86-
87-
---
88-
89-
## 🐙 GitHub Snippet Loader
90-
- Clone any GitHub repository and browse its `.py` files
91-
- Double-click to load into the AI panel as a snippet
92-
- VGroup definitions auto-detected and registered
93-
94-
---
95-
96-
## ⭐ Recents Panel
97-
- Top-5 most-used Mobjects and Animations by actual insertion count
98-
- Persisted to `~/.efficientmanim/usage.json`
99-
- Double-click to instantly add to canvas
100-
101-
---
102-
103-
## ⌨️ Editable Keybindings
104-
- **Help → Edit Keybindings…** — changes apply instantly, no restart
105-
- Duplicate detection; persisted to `QSettings`
106-
107-
---
108-
109-
## 📦 Portable Project Format (.efp)
110-
- ZIP-based: graph JSON + compiled code + all bundled media
111-
- Cross-platform — one file contains everything
112-
📖 Full details: [docs/efp_format.md](docs/efp_format.md)
113-
114-
---
115-
116-
## 🎨 Manim Class Browser
117-
- 60+ Manim classes in 8 categories with real-time search filter
118-
- Double-click or drag to add node to canvas
119-
120-
---
121-
122-
## 🎬 Professional Video Rendering
123-
- Full scene export to MP4/WebM, up to 4K, 15–60 FPS, four quality presets
124-
- Integrated video player for instant review
125-
126-
---
127-
128-
## ✒️ LaTeX Studio
129-
- Live LaTeX preview via MathPad API
130-
- One-click apply to any `MathTex` or `Tex` node
131-
132-
---
133-
134-
## 🔌 Plugin / Extension System
135-
- Extensions in `~/.efficientmanim/ext/<author>/<name>/`
136-
- Permission-gated: nodes, UI panels, timeline tracks, MCP hooks
137-
📖 Full details: [docs/plugin_api.md](docs/plugin_api.md)
138-
139-
---
140-
141-
## 🏠 Home Screen
142-
143-
```bash
144-
python home.py # Home screen with recent projects
145-
python main.py # Open editor directly
146-
```
147-
148-
---
149-
150-
## ⌨️ Keyboard Shortcuts
151-
152-
| Action | Shortcut | Action | Shortcut |
153-
|--------|----------|--------|----------|
154-
| New Project | `Ctrl+N` | Fit View | `Ctrl+0` |
155-
| Open Project | `Ctrl+O` | Zoom In | `Ctrl+=` |
156-
| Save Project | `Ctrl+S` | Zoom Out | `Ctrl+-` |
157-
| Save As | `Ctrl+Shift+S` | Auto-Layout | `Ctrl+L` |
158-
| Exit | `Ctrl+Q` | Export Code | `Ctrl+E` |
159-
| Undo | `Ctrl+Z` | Copy Code | `Ctrl+Shift+C` |
160-
| Redo | `Ctrl+Y` | Render Video | `Ctrl+R` |
161-
| Delete Selected | `Del` | Add Play Node | `Ctrl+Shift+P` |
162-
| Select All | `Ctrl+A` | Add Wait Node | `Ctrl+Shift+W` |
163-
| Create VGroup | `Ctrl+G` | Edit Keybindings | `Ctrl+,` |
164-
165-
📖 Full reference: [docs/shortcuts.md](docs/shortcuts.md)
166-
167-
---
168-
169-
## 📚 Documentation
170-
171-
| Document | Contents |
172-
|---|---|
173-
| [docs/overview.md](docs/overview.md) | Architecture, modules, data flow |
174-
| [docs/setup.md](docs/setup.md) | Installation, requirements, first launch |
175-
| [docs/live_collaboration.md](docs/live_collaboration.md) | PIN sessions, delta sync, network setup |
176-
| [docs/node_reference.md](docs/node_reference.md) | All node types and properties |
177-
| [docs/ai_features.md](docs/ai_features.md) | Code gen, MCP agent, voiceover, LaTeX |
178-
| [docs/shortcuts.md](docs/shortcuts.md) | Full keyboard shortcut reference |
179-
| [docs/efp_format.md](docs/efp_format.md) | Project file format internals |
180-
| [docs/plugin_api.md](docs/plugin_api.md) | Extension / plugin development guide |
181-
| [docs/contributing.md](docs/contributing.md) | Dev setup, code style, PR guide |
182-
183-
---
184-
185-
## 🛠️ Installation
186-
187-
```bash
188-
git clone https://github.com/pro-grammer-SD/EfficientManim.git
189-
cd EfficientManim
190-
pip install -r requirements.txt
191-
python main.py
192-
```
193-
194-
**Requirements:** Python 3.10+, FFmpeg (on PATH), Git, LaTeX (for MathTex)
195-
196-
Full guide: [docs/setup.md](docs/setup.md)
197-
198-
---
199-
200-
## 🌿 About
201-
202-
© 2026 — Soumalya Das (@pro-grammer-SD) · Co-authored with Bailey Beber
203-
Built with PySide6 · Manim · Google Gemini
1+
# EfficientManim
2+
3+
EfficientManim is a node-based Manim editor that helps you build mathematical animations visually, preview quickly, and export clean Python code.
4+
5+
## Highlights
6+
- Visual graph editor for Mobjects and Animations
7+
- Live preview rendering for quick iteration
8+
- Video render pipeline with quality presets
9+
- Gemini-powered helpers for code generation and voiceover
10+
11+
## Quick Start
12+
1. Install dependencies:
13+
```bash
14+
pip install -r requirements.txt
15+
```
16+
2. Run the app:
17+
```bash
18+
python main.py
19+
```
20+
21+
## Documentation
22+
See `docs/README.md` for architecture, workflow, and developer guidance.

app/api/extension_registry.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# ruff: noqa: E402
2+
from PySide6.QtWidgets import QMainWindow
3+
14
"""
25
extension_registry.py — Central registry for extension-provided panels
36
@@ -82,7 +85,7 @@ def realize_panels(self, main_window: "QMainWindow") -> Dict[str, Any]:
8285
"""
8386
Create and add all registered panels to the main window.
8487
85-
Called once after EfficientManimWindow.__init__() completes.
88+
Called once after __import__('ui.main_window').main_window.EfficientManimWindow.__init__() completes.
8689
8790
Returns:
8891
{panel_name: widget_instance} for all successfully created panels

app/app_window.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from __future__ import annotations
2+
# -*- coding: utf-8 -*-
3+
4+
from core.project_manager import ProjectManager
5+
6+
7+
def create_main_window():
8+
from ui.main_window import EfficientManimWindow
9+
window = EfficientManimWindow()
10+
window.project_manager = ProjectManager(window)
11+
return window

app/autosave_manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def __init__(self):
5454
self._last_assets_hash = ""
5555
self._last_keybindings_hash = ""
5656

57-
# Compute functions (will be set by EfficientManimWindow)
57+
# Compute functions (will be set by __import__('ui.main_window').main_window.EfficientManimWindow)
5858
self._compute_code_hash: Optional[Callable[[], str]] = None
5959
self._compute_graph_hash: Optional[Callable[[], str]] = None
6060
self._compute_assets_hash: Optional[Callable[[], str]] = None

app/extensions/animation_presets.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# ruff: noqa: E402
2+
from __future__ import annotations
3+
14
"""
25
Animation Presets Extension — ✨ Quick Effects
36
@@ -17,8 +20,6 @@
1720
can execute immediately.
1821
"""
1922

20-
from __future__ import annotations
21-
2223
import logging
2324
import textwrap
2425
from typing import TYPE_CHECKING
@@ -370,7 +371,7 @@ def _get_selected_object_name(self) -> str:
370371
"""
371372
Return the Python variable name for the currently selected graph node.
372373
373-
Walks up the widget tree to find EfficientManimWindow and inspects its
374+
Walks up the widget tree to find __import__('ui.main_window').main_window.EfficientManimWindow and inspects its
374375
`scene.selectedItems()`. Falls back to self._selected_obj.
375376
"""
376377
try:
@@ -456,21 +457,27 @@ def _inject_and_render(self, preset_name: str, snippet: str, obj_name: str) -> b
456457
# ── Window helpers ────────────────────────────────────────────────────────
457458

458459
def _get_main_window(self):
459-
"""Walk widget tree to find EfficientManimWindow."""
460+
"""Walk widget tree to find __import__('ui.main_window').main_window.EfficientManimWindow."""
460461
if self._main_window is not None:
461462
return self._main_window
462463
widget = self
463464
while widget is not None:
464465
# Import lazily to avoid circular deps at module load time
465-
if type(widget).__name__ == "EfficientManimWindow":
466+
if (
467+
type(widget).__name__
468+
== "__import__('ui.main_window').main_window.EfficientManimWindow"
469+
):
466470
self._main_window = widget
467471
return widget
468472
widget = widget.parent()
469473
# Fallback: search QApplication top-level windows
470474
app = QApplication.instance()
471475
if app:
472476
for w in app.topLevelWidgets():
473-
if type(w).__name__ == "EfficientManimWindow":
477+
if (
478+
type(w).__name__
479+
== "__import__('ui.main_window').main_window.EfficientManimWindow"
480+
):
474481
self._main_window = w
475482
return w
476483
return None

app/extensions/color_palette.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ def _darken_color(hex_color: str, factor: float = 0.8) -> str:
284284
color.alpha(),
285285
)
286286
return color.name()
287-
except:
287+
except Exception:
288288
return "#1d4ed8" # Default dark blue
289289

290290
@staticmethod
@@ -299,7 +299,7 @@ def _lighten_color(hex_color: str, factor: float = 0.3) -> str:
299299
color.alpha(),
300300
)
301301
return color.name()
302-
except:
302+
except Exception:
303303
return "#dbeafe" # Default light blue
304304

305305
def get_palette(self, name: str) -> list:

app/extensions/math_symbols.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def setup(api):
5454

5555

5656
try:
57-
from manim import Tex, VGroup
57+
from manim import Tex
5858

5959
MANIM_AVAILABLE = True
6060
except ImportError:

app/keybinding_registry.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
from dataclasses import dataclass
3535

3636
try:
37-
from PySide6.QtCore import QObject, Signal, QSettings
38-
from PySide6.QtGui import QKeySequence
37+
from PySide6.QtCore import QObject, Signal
38+
3939

4040
HAS_PYSIDE = True
4141
except ImportError:

app/layout_persistence.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import json
1919
import logging
2020
from pathlib import Path
21-
from typing import Dict, Any, Optional
21+
from typing import Dict, Any, Optional, Tuple
2222

2323
LOGGER = logging.getLogger("layout_persistence")
2424

0 commit comments

Comments
 (0)