A production-ready Python overlay editor for OBS Studio. Design real-time text messages, shapes, stickers, and smoke effects — then push them live to your stream via a Browser Source.
| Category | Capabilities |
|---|---|
| Text | Custom TTF/OTF fonts, solid/gradient fills, per-character styles, alignment, letter/line spacing |
| Effects | Drop Shadow, Glow, Stroke (outline), Bevel/Emboss, Texturize |
| Transitions | Fade, Fly From Left/Right/Top/Bottom, Drop In, Roll On, Zoom In, Bounce In, Spin & Scale, Elastic Bounce, Wipe, Typewriter, Particle Burst |
| Animations | Audio Bounce (mic/system audio reactive), Pulse, Wave, Float, Shake, Spin, Rainbow |
| Shapes | Rectangle, Rounded Rect, Circle, Ellipse, Line — solid or gradient fill, stroke |
| Stickers | PNG/JPG images with transparency, scale, flip, rotate |
| Smoke | CPU particle system: density, speed, direction, turbulence, color, particle size |
| Layers | Unlimited layers, z-order reordering, visibility toggle, duplicate |
| Presets | 4 built-in + save/load unlimited custom presets (JSON) |
| Export | Browser Source (HTML/CSS/JS) served locally; OBS WebSocket script |
obsmsgplug/
├── overlay_editor.py # ← Launch this to open the GUI
├── requirements.txt
├── README.md
│
├── obs/
│ └── obs_script.py # ← Load this in OBS → Tools → Scripts
│
├── src/
│ ├── models/ # Data models (layer types, project)
│ │ ├── layer.py # TextLayer, ShapeLayer, StickerLayer, SmokeLayer
│ │ └── project.py # Project, Scene, CanvasSettings
│ │
│ ├── rendering/ # Pillow/NumPy rendering pipeline
│ │ ├── renderer.py # Main compositor
│ │ ├── text_renderer.py # Per-character text with effects
│ │ ├── effects.py # Shadow, glow, stroke, bevel
│ │ ├── particles.py # Smoke particle system
│ │ └── animations.py # Easing functions, transition & animation engine
│ │
│ ├── audio/
│ │ └── analyzer.py # Real-time audio RMS + beat detection
│ │
│ ├── server/
│ │ └── overlay_server.py # Flask + Socket.IO HTTP/WebSocket server
│ │
│ ├── ui/
│ │ ├── main_window.py # Main PyQt5 window
│ │ ├── preview_widget.py # Live 30fps preview (QPainter)
│ │ ├── layers_panel.py # Layer stack management
│ │ ├── text_tab.py # Text properties
│ │ ├── style_tab.py # Shadow/glow/stroke/bevel
│ │ ├── animation_tab.py # Transitions & animations
│ │ ├── shapes_tab.py # Shape & sticker properties
│ │ ├── overlays_tab.py # Smoke overlay properties
│ │ └── color_picker_widget.py # Color + gradient picker
│ │
│ └── utils/
│ ├── config.py # App settings (~/.config/)
│ └── presets.py # Built-in & custom presets
│
├── browser_source/
│ ├── overlay.html # HTML served to OBS Browser Source
│ ├── overlay.css # Styles & CSS keyframe animations
│ └── overlay.js # JS renderer + smoke particle system
│
└── assets/
├── fonts/ # Drop custom fonts here
├── stickers/ # Drop PNG stickers here
└── presets/ # User-saved preset JSON files
- Python 3.10 or newer
- OBS Studio 28+ (for WebSocket v5 / Browser Source)
pippackage manager
cd /path/to/obsmsgplug
pip install -r requirements.txtKey packages:
PyQt5— GUI frameworkPillow— image & text renderingnumpy,scipy— animation math, audio analysissounddevice— real-time audio captureflask,flask-socketio,eventlet— local Browser Source server
python overlay_editor.pyThe editor opens with a dark-themed UI, a live preview, and a layer stack.
- Start the overlay server: Server → Start / Restart Server (auto-starts on launch)
- In OBS, add a Browser Source:
- Right-click your scene → Add → Browser
- URL:
http://localhost:8765/overlay - Width:
1920, Height:1080 - ✅ Enable "Shutdown source when not visible"
- Done! Changes in the editor appear live in OBS.
- Open OBS → Tools → Scripts
- Click + and select
obs/obs_script.py - In OBS → Tools → Scripts → Python Settings, set your Python 3 executable
- The script will auto-create the Browser Source and register show/hide hotkeys
Note: The OBS Python scripting API (
obspython) is only available when running inside OBS. The standalone editor (overlay_editor.py) runs independently and communicates via the local HTTP server.
- Launch
overlay_editor.py - Click + Text in the toolbar or Layers panel
- In the Text tab on the right:
- Type your message in the text box
- Choose a font (click Browse… to load a TTF/OTF)
- Set font size and color
- In the Style tab, enable Glow or Shadow for visual impact
- In the Animation tab, set an Entrance Transition (e.g. Fly From Left)
- Watch the live preview update in real-time
- Connect OBS via Browser Source (see above) to go live
- Toolbar dropdown → pick a preset, or
- Menu: Presets → Load Preset
Built-in presets:
| Preset | Description |
|---|---|
| Neon Glow Announcement | Gradient "NOW LIVE" with cyan glow, elastic zoom-in |
| Subtle Smoke Lower Third | Name/title banner with soft smoke background |
| Typewriter Alert | Follower alert that types itself out character by character |
| Audio Bounce Title | Beat-reactive title that bounces to music |
To style individual characters differently:
- Select a text layer
- In the Text tab, the char_styles list is managed programmatically
- Via JSON project file, add entries to
char_stylesarray:
"char_styles": [
{ "char": "H", "fill": {"fill_type": "solid", "color": [255,0,0,255]}, "font_size": 72 },
{ "char": "i", "fill": {"fill_type": "solid", "color": [0,255,0,255]} }
]Full per-character UI editor is on the roadmap for v1.1.
- Menu: Audio → Enable Audio Analysis
- Select a text layer → Animation tab
- Set Type = "Audio Bounce"
- Enable ✅ "React to audio input"
- The text will bounce and scale with your microphone/system audio
The audio analyzer uses sounddevice to capture input, performs FFT-based beat detection, and feeds the amplitude to the animation engine in real-time.
- Click + Smoke in the Layers panel
- In the Smoke tab:
- Density: How many particles spawn per second (0.0–1.0)
- Speed: Particle drift velocity
- Direction: 270° = upward, 90° = downward, 0° = right
- Turbulence: Randomness / swirl in particle paths
- Particle color: RGBA (alpha controls transparency)
- Emitter Y: Set to 1.0 to emit from the bottom of screen
The smoke renders in both the Python preview (Pillow particles) and the browser source (HTML Canvas particles). The JavaScript version is smoother and recommended for the final output.
- Ctrl+S — Save project (
.omolayJSON format) - Ctrl+Shift+S — Save As
- Ctrl+O — Open project
- File → Recent Files — Quick access to recent projects
Projects are standard JSON and can be version-controlled.
- Add an entry to
TransitionEffectenum insrc/models/layer.py - Handle it in
AnimationEngine.get_transform()insrc/rendering/animations.py - Add a CSS
@keyframesrule inbrowser_source/overlay.css - Add the mapping in
TRANSITION_ANIMATIONSinbrowser_source/overlay.js
- Add to
AnimationTypeenum - Handle in
AnimationEngine.get_transform() - Add CSS animation + JS handling in browser_source files
Add to ShapeType enum and handle in OverlayRenderer._render_shape() (Python) and renderShapeLayer() (JS).
| Concern | Detail |
|---|---|
| Preview FPS | Target 30fps; complex text effects (glow+stroke+bevel) may drop to 15fps on slower machines. Disable effects to improve preview speed; they still render in the browser source. |
| Smoke particles | Browser source renders ≈ 30–80 particles smoothly via Canvas 2D. Python preview is intentionally limited for performance. |
| Text rendering | Pillow renders text per-frame. For long strings with many effects, consider caching: store the rendered image and only re-render when the layer changes (TODO for v1.1). |
| Browser Source | The JS renderer in OBS's Chromium engine is significantly faster than the Python preview. Always test your final design in OBS. |
- Use Browser Source (Chromium rendering is hardware-accelerated)
- Set a reasonable frame rate in OBS Scene settings
- Disable "Shutdown source when not visible" if experiencing flash-in
Server won't start / Flask error
pip install flask flask-socketio eventletAudio not working
pip install sounddevice
# On Linux, also: sudo apt install libportaudio2PyQt5 install fails on Linux
sudo apt install python3-pyqt5
# or
pip install PyQt5 --config-settings --confirm-licenseFonts not loading
- Use absolute paths, or place fonts in
assets/fonts/ - Supported formats:
.ttf,.otf,.ttc - Test with:
python -c "from PIL import ImageFont; ImageFont.truetype('your_font.ttf', 48)"
OBS Browser Source shows blank white page
- Check that the server is running (green indicator in editor)
- Verify the URL is exactly
http://localhost:8765/overlay - In OBS browser source settings, click "Refresh cache of current page"
scipy not available (stroke effect fallback)
pip install scipyWithout scipy, the stroke effect uses a simpler single-pixel outline.
MIT License. See LICENSE file.
- Full per-character style UI editor
- OpenGL-based smoke renderer (10x more particles)
- OBS WebSocket v5 direct integration (scene switching triggers)
- Twitch/YouTube alert webhook integration
- Video/GIF sticker support
- Text rendering cache for improved preview performance
- Multi-monitor preview
- Export to standalone HTML file (no server required)