puppetcam 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- puppetcam-0.1.0/LICENSE +21 -0
- puppetcam-0.1.0/PKG-INFO +253 -0
- puppetcam-0.1.0/README.md +224 -0
- puppetcam-0.1.0/pyproject.toml +59 -0
- puppetcam-0.1.0/setup.cfg +4 -0
- puppetcam-0.1.0/src/puppetcam/__init__.py +3 -0
- puppetcam-0.1.0/src/puppetcam/__main__.py +3 -0
- puppetcam-0.1.0/src/puppetcam/app.py +124 -0
- puppetcam-0.1.0/src/puppetcam/audio.py +70 -0
- puppetcam-0.1.0/src/puppetcam/avatars/__init__.py +3 -0
- puppetcam-0.1.0/src/puppetcam/avatars/base.py +62 -0
- puppetcam-0.1.0/src/puppetcam/avatars/sprout.py +278 -0
- puppetcam-0.1.0/src/puppetcam/capture.py +122 -0
- puppetcam-0.1.0/src/puppetcam/cli.py +199 -0
- puppetcam-0.1.0/src/puppetcam/doctor.py +96 -0
- puppetcam-0.1.0/src/puppetcam/engine.py +85 -0
- puppetcam-0.1.0/src/puppetcam/filters.py +74 -0
- puppetcam-0.1.0/src/puppetcam/idle.py +58 -0
- puppetcam-0.1.0/src/puppetcam/mapping.py +163 -0
- puppetcam-0.1.0/src/puppetcam/params.py +54 -0
- puppetcam-0.1.0/src/puppetcam/platform_tweaks.py +76 -0
- puppetcam-0.1.0/src/puppetcam/presence.py +44 -0
- puppetcam-0.1.0/src/puppetcam/sinks.py +88 -0
- puppetcam-0.1.0/src/puppetcam/themes/alien.toml +21 -0
- puppetcam-0.1.0/src/puppetcam/themes/mint.toml +16 -0
- puppetcam-0.1.0/src/puppetcam/themes/office.toml +15 -0
- puppetcam-0.1.0/src/puppetcam/themes/sprout.toml +43 -0
- puppetcam-0.1.0/src/puppetcam/themes/winter.toml +13 -0
- puppetcam-0.1.0/src/puppetcam/themes.py +178 -0
- puppetcam-0.1.0/src/puppetcam/tools.py +115 -0
- puppetcam-0.1.0/src/puppetcam/tracker.py +188 -0
- puppetcam-0.1.0/src/puppetcam.egg-info/PKG-INFO +253 -0
- puppetcam-0.1.0/src/puppetcam.egg-info/SOURCES.txt +37 -0
- puppetcam-0.1.0/src/puppetcam.egg-info/dependency_links.txt +1 -0
- puppetcam-0.1.0/src/puppetcam.egg-info/entry_points.txt +5 -0
- puppetcam-0.1.0/src/puppetcam.egg-info/requires.txt +12 -0
- puppetcam-0.1.0/src/puppetcam.egg-info/top_level.txt +1 -0
- puppetcam-0.1.0/tests/test_core.py +178 -0
- puppetcam-0.1.0/tests/test_themes_platform.py +138 -0
puppetcam-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 puppetcam contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
puppetcam-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: puppetcam
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An animated avatar for your video calls. Runs 100% locally on CPU, no training, no cloud.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/cesaredavidepace/puppetcam
|
|
7
|
+
Project-URL: Issues, https://github.com/cesaredavidepace/puppetcam/issues
|
|
8
|
+
Keywords: avatar,webcam,virtual camera,face tracking,mediapipe,video calls
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
11
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
12
|
+
Classifier: Operating System :: MacOS
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Multimedia :: Video :: Capture
|
|
16
|
+
Requires-Python: >=3.11
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: mediapipe>=0.10.14
|
|
20
|
+
Requires-Dist: numpy>=1.24
|
|
21
|
+
Requires-Dist: certifi
|
|
22
|
+
Requires-Dist: pyvirtualcam>=0.11
|
|
23
|
+
Requires-Dist: appnope>=0.1.3; sys_platform == "darwin"
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
26
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
27
|
+
Requires-Dist: imageio>=2.30; extra == "dev"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# puppetcam
|
|
31
|
+
|
|
32
|
+
**An animated avatar for your video calls. Runs 100% locally, on CPU, with no training and no cloud.**
|
|
33
|
+
|
|
34
|
+
Camera off in a meeting feels like a black hole; camera on isn't always an option.
|
|
35
|
+
puppetcam turns your webcam into a cartoon that moves like you: head, eyes, brows,
|
|
36
|
+
mouth. Zoom, Meet, Teams and anything else just see a normal webcam.
|
|
37
|
+
|
|
38
|
+

|
|
39
|
+
|
|
40
|
+
- **Works everywhere:** shows up as a virtual camera, not a plugin for one app.
|
|
41
|
+
- **Light:** a few milliseconds of rendering per frame, no GPU needed.
|
|
42
|
+
- **Private:** frames and audio are processed in memory and never leave your machine.
|
|
43
|
+
The only network access is a one-time download of the face model (a few MB).
|
|
44
|
+
- **Away mode:** step away and the avatar keeps blinking, breathing and lip-syncing
|
|
45
|
+
to your microphone instead of freezing.
|
|
46
|
+
- **Yours:** colors, proportions, accessories and background come from a small theme file.
|
|
47
|
+
- **Hackable:** an avatar is one Python class. Add your own as a plugin.
|
|
48
|
+
|
|
49
|
+
> Status: alpha. Expect rough edges, and please open issues.
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
52
|
+
|
|
53
|
+
**1. Install a virtual camera backend** (one time):
|
|
54
|
+
|
|
55
|
+
| OS | What to install |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| Windows | [OBS Studio](https://obsproject.com). It ships the "OBS Virtual Camera" driver. Run it once, then quit it. |
|
|
58
|
+
| macOS | OBS Studio 30+. Start and stop its Virtual Camera once, allow it (see below), then quit OBS. |
|
|
59
|
+
| Linux | `sudo apt install v4l2loopback-dkms` then `sudo modprobe v4l2loopback devices=1 exclusive_caps=1 card_label="puppetcam"` |
|
|
60
|
+
|
|
61
|
+
**2. Install and run** (Python 3.11+):
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install puppetcam
|
|
65
|
+
puppetcam doctor # checks camera, face model, microphone and virtual camera
|
|
66
|
+
puppetcam
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Look at the camera for half a second with a relaxed face while it calibrates. Then in your
|
|
70
|
+
meeting app pick **"OBS Virtual Camera"** (or "puppetcam" on Linux) as the camera.
|
|
71
|
+
|
|
72
|
+
> You don't need OBS open: puppetcam sends its frames into the OBS Virtual Camera itself.
|
|
73
|
+
> If you start the Virtual Camera from OBS, you'll see OBS's (empty) scene instead of the avatar.
|
|
74
|
+
|
|
75
|
+
Preview window keys: `q` quit · `c` recalibrate · `a` toggle away mode · `b` toggle the AVATAR badge.
|
|
76
|
+
|
|
77
|
+
### In Google Meet, Microsoft Teams and Zoom
|
|
78
|
+
|
|
79
|
+
- **Start puppetcam before joining.** If the meeting app or browser was already open and
|
|
80
|
+
doesn't list the camera, restart it.
|
|
81
|
+
- **Meet:** Settings → Video → Camera. **Teams:** Settings → Devices → Camera.
|
|
82
|
+
**Zoom:** Settings → Video → Camera.
|
|
83
|
+
- **Turn off background blur and virtual backgrounds** in the meeting app: they try to cut a
|
|
84
|
+
person out of the cartoon. Change the background with a [theme](#themes-make-it-yours) instead.
|
|
85
|
+
- Your own self-view may show the AVATAR badge mirrored. Others see it the right way round.
|
|
86
|
+
- Small expressions too subtle? Try `puppetcam --sensitivity 2` (default 1.5), and press `c`
|
|
87
|
+
to recalibrate with a relaxed face. If the avatar jitters while you're still, go down to 1.2.
|
|
88
|
+
|
|
89
|
+
### Platform notes
|
|
90
|
+
|
|
91
|
+
**Windows**
|
|
92
|
+
- The camera is opened with DirectShow + MJPG: it starts in well under a second, where
|
|
93
|
+
Media Foundation can take several.
|
|
94
|
+
- Use Python 3.11 or newer: older versions sleep in ~15 ms steps on Windows, which makes the
|
|
95
|
+
frame rate uneven.
|
|
96
|
+
- While you're away, the tracking thread switches to Windows 11 "efficiency mode" (EcoQoS).
|
|
97
|
+
|
|
98
|
+
**macOS**
|
|
99
|
+
- Allow the virtual camera: on macOS 26 (Tahoe) it's under **System Settings → Privacy &
|
|
100
|
+
Security → Extensions → OBS → Media Extension**; on older versions under Login Items &
|
|
101
|
+
Extensions → Camera Extensions. Then restart OBS once.
|
|
102
|
+
- Camera permission is asked for the app you launch from (Terminal, iTerm, VS Code...).
|
|
103
|
+
- Use a native arm64 Python on Apple Silicon (not x86 under Rosetta, which is much slower).
|
|
104
|
+
- Try `--gpu`: MediaPipe can run on Metal, which is faster than CPU on Apple Silicon.
|
|
105
|
+
- App Nap is disabled automatically, so macOS doesn't throttle puppetcam while your meeting app
|
|
106
|
+
is in front.
|
|
107
|
+
|
|
108
|
+
**Linux**
|
|
109
|
+
- **Start puppetcam before opening the meeting in the browser.** With `exclusive_caps=1`, Chrome
|
|
110
|
+
only lists the virtual camera once frames are flowing into it.
|
|
111
|
+
- `--gpu` works only with MediaPipe wheels built with GPU support; otherwise it falls back to CPU.
|
|
112
|
+
|
|
113
|
+
## Something doesn't work?
|
|
114
|
+
|
|
115
|
+
Run `puppetcam doctor` and paste its output into a
|
|
116
|
+
[new issue](https://github.com/cesaredavidepace/puppetcam/issues/new/choose). It shows your OS,
|
|
117
|
+
Python, camera, microphone and virtual camera status in a few lines.
|
|
118
|
+
|
|
119
|
+
## Useful options
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
puppetcam --size 1280x720 # output resolution (default 960x540)
|
|
123
|
+
puppetcam --theme office # pick a theme (see below)
|
|
124
|
+
puppetcam --track-fps 15 # track at 15 Hz: about half the CPU, still smooth
|
|
125
|
+
puppetcam --gpu # try GPU tracking, falls back to CPU if unavailable
|
|
126
|
+
puppetcam --no-preview # headless
|
|
127
|
+
puppetcam --no-vcam # just the preview window, to try it out
|
|
128
|
+
puppetcam --invert-yaw # if the avatar turns the wrong way (also pitch/roll)
|
|
129
|
+
puppetcam --swap-eyes # if it winks with the wrong eye
|
|
130
|
+
puppetcam --sensitivity 2 # exaggerate small movements more (default 1.5, 1 = linear)
|
|
131
|
+
puppetcam bench --video 0 # measure tracking and render cost on your machine
|
|
132
|
+
puppetcam demo demo.mp4 # render a scripted clip, no webcam needed
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Themes: make it yours
|
|
136
|
+
|
|
137
|
+

|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
puppetcam themes # list built-in themes
|
|
141
|
+
puppetcam --theme winter # use one
|
|
142
|
+
puppetcam themes --export sprout my-theme.toml # copy the full template
|
|
143
|
+
puppetcam themes --check my-theme.toml # validate your edits
|
|
144
|
+
puppetcam --theme my-theme.toml
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
A theme only needs what it changes. A blue sweater, glasses and your own background:
|
|
148
|
+
|
|
149
|
+
```toml
|
|
150
|
+
name = "Me"
|
|
151
|
+
|
|
152
|
+
[colors]
|
|
153
|
+
sweater = "#3B6FD4"
|
|
154
|
+
|
|
155
|
+
[accessories]
|
|
156
|
+
items = ["glasses"] # sprout, glasses, beanie, headphones
|
|
157
|
+
|
|
158
|
+
[background]
|
|
159
|
+
image = "my-office.jpg" # relative to this file; cropped to fill
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Everything you can set (colors, head roundness and proportions, eye size and spacing, mouth
|
|
163
|
+
width, body width, accessories, background) is listed with comments in
|
|
164
|
+
[`themes/sprout.toml`](src/puppetcam/themes/sprout.toml). Shades like `skin_shade` are derived
|
|
165
|
+
automatically unless you set them. Themes cost nothing at runtime: they're applied once at startup.
|
|
166
|
+
|
|
167
|
+
## How it works
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
webcam ──► sensor thread ─────────────────────► render loop (30 fps) ──► virtual camera
|
|
171
|
+
capture 640x480 mapping + calibration
|
|
172
|
+
MediaPipe Face Landmarker presence: tracking / hold / away
|
|
173
|
+
(52 blendshapes + head pose) idle animator + mic level
|
|
174
|
+
One Euro smoothing
|
|
175
|
+
avatar.render(params)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
1. **Tracking:** [MediaPipe Face Landmarker](https://ai.google.dev/edge/mediapipe/solutions/vision/face_landmarker)
|
|
179
|
+
gives 52 ARKit-style blendshape scores (jaw open, blink, smile...) and the head rotation.
|
|
180
|
+
Pre-trained and used as-is.
|
|
181
|
+
2. **Mapping:** plain arithmetic turns those into 11 normalized parameters (`AvatarParams`),
|
|
182
|
+
relative to your resting face captured at startup.
|
|
183
|
+
3. **Presence:** if your face disappears, the avatar holds its pose for a moment, then fades
|
|
184
|
+
into idle animation with mouth driven by microphone loudness.
|
|
185
|
+
4. **Smoothing:** a [One Euro filter](https://gery.casiez.net/1euro/) removes jitter without adding lag.
|
|
186
|
+
5. **Rendering:** the default avatar is drawn with anti-aliased OpenCV polygons. The 3D effect
|
|
187
|
+
is parallax: features slide, the far eye narrows, ears move the other way, the leaf bounces on a spring.
|
|
188
|
+
|
|
189
|
+
Performance notes and measurements: [docs/optimization.md](docs/optimization.md).
|
|
190
|
+
|
|
191
|
+
## Privacy and honesty
|
|
192
|
+
|
|
193
|
+
- No frames, audio or landmarks are saved or sent anywhere.
|
|
194
|
+
- The **AVATAR badge is on by default**. People in a call deserve to know they are looking at
|
|
195
|
+
an avatar. You can hide it, but please tell them.
|
|
196
|
+
|
|
197
|
+
## Write your own avatar
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
from puppetcam.avatars import Avatar
|
|
201
|
+
from puppetcam.params import AvatarParams
|
|
202
|
+
|
|
203
|
+
class MyAvatar(Avatar):
|
|
204
|
+
name = "mine"
|
|
205
|
+
def render(self, p: AvatarParams, dt: float):
|
|
206
|
+
... # return an HxWx3 uint8 BGR image
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Register it from your own package, no fork needed:
|
|
210
|
+
|
|
211
|
+
```toml
|
|
212
|
+
[project.entry-points."puppetcam.avatars"]
|
|
213
|
+
mine = "my_package.avatar:MyAvatar"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Then `puppetcam --avatar mine`. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
217
|
+
|
|
218
|
+
## Roadmap
|
|
219
|
+
|
|
220
|
+
What's coming next. Priorities follow your feedback: open an
|
|
221
|
+
[issue](https://github.com/cesaredavidepace/puppetcam/issues/new/choose) or a
|
|
222
|
+
[discussion](https://github.com/cesaredavidepace/puppetcam/discussions) to push for something.
|
|
223
|
+
|
|
224
|
+
**v0.1 — now: for people comfortable with a terminal**
|
|
225
|
+
|
|
226
|
+
- [x] Cartoon avatar as a virtual camera for Meet, Teams, Zoom and any other app
|
|
227
|
+
- [x] Away mode, themes, avatar plugins
|
|
228
|
+
- [x] `--sensitivity` for small movements, `puppetcam doctor` to check your setup
|
|
229
|
+
|
|
230
|
+
**v0.2 — no terminal needed**
|
|
231
|
+
|
|
232
|
+
- [ ] Settings saved in a file: theme, camera, sensitivity, badge. No more command-line flags
|
|
233
|
+
- [ ] Menu bar app (macOS) and tray app (Windows): on/off, theme, sensitivity, recalibrate,
|
|
234
|
+
start at login
|
|
235
|
+
- [ ] One-click installers: a signed app for macOS and an installer for Windows, with the face
|
|
236
|
+
model included (no download on first run)
|
|
237
|
+
|
|
238
|
+
**v0.3 — make your own character**
|
|
239
|
+
|
|
240
|
+
- [ ] Draw-your-own avatar from a few PNG layers (head, eyes, mouth shapes), no code needed
|
|
241
|
+
- [ ] More themes and avatars from the community
|
|
242
|
+
|
|
243
|
+
**Later**
|
|
244
|
+
|
|
245
|
+
- [ ] Own virtual camera, so OBS is no longer required (Windows 11 and macOS)
|
|
246
|
+
- [ ] Upper body: shoulders and hands from MediaPipe Pose Landmarker (lite)
|
|
247
|
+
- [ ] "Your photo" avatar: animate a single photo by mesh warping, still CPU-only
|
|
248
|
+
- [ ] Adaptive tracking rate (slow down when you're still, not only when away)
|
|
249
|
+
|
|
250
|
+
## License
|
|
251
|
+
|
|
252
|
+
MIT, see [LICENSE](LICENSE). The face model is downloaded from Google's MediaPipe
|
|
253
|
+
model storage and is not redistributed here; it is covered by its own model card and license.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# puppetcam
|
|
2
|
+
|
|
3
|
+
**An animated avatar for your video calls. Runs 100% locally, on CPU, with no training and no cloud.**
|
|
4
|
+
|
|
5
|
+
Camera off in a meeting feels like a black hole; camera on isn't always an option.
|
|
6
|
+
puppetcam turns your webcam into a cartoon that moves like you: head, eyes, brows,
|
|
7
|
+
mouth. Zoom, Meet, Teams and anything else just see a normal webcam.
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
- **Works everywhere:** shows up as a virtual camera, not a plugin for one app.
|
|
12
|
+
- **Light:** a few milliseconds of rendering per frame, no GPU needed.
|
|
13
|
+
- **Private:** frames and audio are processed in memory and never leave your machine.
|
|
14
|
+
The only network access is a one-time download of the face model (a few MB).
|
|
15
|
+
- **Away mode:** step away and the avatar keeps blinking, breathing and lip-syncing
|
|
16
|
+
to your microphone instead of freezing.
|
|
17
|
+
- **Yours:** colors, proportions, accessories and background come from a small theme file.
|
|
18
|
+
- **Hackable:** an avatar is one Python class. Add your own as a plugin.
|
|
19
|
+
|
|
20
|
+
> Status: alpha. Expect rough edges, and please open issues.
|
|
21
|
+
|
|
22
|
+
## Quick start
|
|
23
|
+
|
|
24
|
+
**1. Install a virtual camera backend** (one time):
|
|
25
|
+
|
|
26
|
+
| OS | What to install |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| Windows | [OBS Studio](https://obsproject.com). It ships the "OBS Virtual Camera" driver. Run it once, then quit it. |
|
|
29
|
+
| macOS | OBS Studio 30+. Start and stop its Virtual Camera once, allow it (see below), then quit OBS. |
|
|
30
|
+
| Linux | `sudo apt install v4l2loopback-dkms` then `sudo modprobe v4l2loopback devices=1 exclusive_caps=1 card_label="puppetcam"` |
|
|
31
|
+
|
|
32
|
+
**2. Install and run** (Python 3.11+):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install puppetcam
|
|
36
|
+
puppetcam doctor # checks camera, face model, microphone and virtual camera
|
|
37
|
+
puppetcam
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Look at the camera for half a second with a relaxed face while it calibrates. Then in your
|
|
41
|
+
meeting app pick **"OBS Virtual Camera"** (or "puppetcam" on Linux) as the camera.
|
|
42
|
+
|
|
43
|
+
> You don't need OBS open: puppetcam sends its frames into the OBS Virtual Camera itself.
|
|
44
|
+
> If you start the Virtual Camera from OBS, you'll see OBS's (empty) scene instead of the avatar.
|
|
45
|
+
|
|
46
|
+
Preview window keys: `q` quit · `c` recalibrate · `a` toggle away mode · `b` toggle the AVATAR badge.
|
|
47
|
+
|
|
48
|
+
### In Google Meet, Microsoft Teams and Zoom
|
|
49
|
+
|
|
50
|
+
- **Start puppetcam before joining.** If the meeting app or browser was already open and
|
|
51
|
+
doesn't list the camera, restart it.
|
|
52
|
+
- **Meet:** Settings → Video → Camera. **Teams:** Settings → Devices → Camera.
|
|
53
|
+
**Zoom:** Settings → Video → Camera.
|
|
54
|
+
- **Turn off background blur and virtual backgrounds** in the meeting app: they try to cut a
|
|
55
|
+
person out of the cartoon. Change the background with a [theme](#themes-make-it-yours) instead.
|
|
56
|
+
- Your own self-view may show the AVATAR badge mirrored. Others see it the right way round.
|
|
57
|
+
- Small expressions too subtle? Try `puppetcam --sensitivity 2` (default 1.5), and press `c`
|
|
58
|
+
to recalibrate with a relaxed face. If the avatar jitters while you're still, go down to 1.2.
|
|
59
|
+
|
|
60
|
+
### Platform notes
|
|
61
|
+
|
|
62
|
+
**Windows**
|
|
63
|
+
- The camera is opened with DirectShow + MJPG: it starts in well under a second, where
|
|
64
|
+
Media Foundation can take several.
|
|
65
|
+
- Use Python 3.11 or newer: older versions sleep in ~15 ms steps on Windows, which makes the
|
|
66
|
+
frame rate uneven.
|
|
67
|
+
- While you're away, the tracking thread switches to Windows 11 "efficiency mode" (EcoQoS).
|
|
68
|
+
|
|
69
|
+
**macOS**
|
|
70
|
+
- Allow the virtual camera: on macOS 26 (Tahoe) it's under **System Settings → Privacy &
|
|
71
|
+
Security → Extensions → OBS → Media Extension**; on older versions under Login Items &
|
|
72
|
+
Extensions → Camera Extensions. Then restart OBS once.
|
|
73
|
+
- Camera permission is asked for the app you launch from (Terminal, iTerm, VS Code...).
|
|
74
|
+
- Use a native arm64 Python on Apple Silicon (not x86 under Rosetta, which is much slower).
|
|
75
|
+
- Try `--gpu`: MediaPipe can run on Metal, which is faster than CPU on Apple Silicon.
|
|
76
|
+
- App Nap is disabled automatically, so macOS doesn't throttle puppetcam while your meeting app
|
|
77
|
+
is in front.
|
|
78
|
+
|
|
79
|
+
**Linux**
|
|
80
|
+
- **Start puppetcam before opening the meeting in the browser.** With `exclusive_caps=1`, Chrome
|
|
81
|
+
only lists the virtual camera once frames are flowing into it.
|
|
82
|
+
- `--gpu` works only with MediaPipe wheels built with GPU support; otherwise it falls back to CPU.
|
|
83
|
+
|
|
84
|
+
## Something doesn't work?
|
|
85
|
+
|
|
86
|
+
Run `puppetcam doctor` and paste its output into a
|
|
87
|
+
[new issue](https://github.com/cesaredavidepace/puppetcam/issues/new/choose). It shows your OS,
|
|
88
|
+
Python, camera, microphone and virtual camera status in a few lines.
|
|
89
|
+
|
|
90
|
+
## Useful options
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
puppetcam --size 1280x720 # output resolution (default 960x540)
|
|
94
|
+
puppetcam --theme office # pick a theme (see below)
|
|
95
|
+
puppetcam --track-fps 15 # track at 15 Hz: about half the CPU, still smooth
|
|
96
|
+
puppetcam --gpu # try GPU tracking, falls back to CPU if unavailable
|
|
97
|
+
puppetcam --no-preview # headless
|
|
98
|
+
puppetcam --no-vcam # just the preview window, to try it out
|
|
99
|
+
puppetcam --invert-yaw # if the avatar turns the wrong way (also pitch/roll)
|
|
100
|
+
puppetcam --swap-eyes # if it winks with the wrong eye
|
|
101
|
+
puppetcam --sensitivity 2 # exaggerate small movements more (default 1.5, 1 = linear)
|
|
102
|
+
puppetcam bench --video 0 # measure tracking and render cost on your machine
|
|
103
|
+
puppetcam demo demo.mp4 # render a scripted clip, no webcam needed
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Themes: make it yours
|
|
107
|
+
|
|
108
|
+

|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
puppetcam themes # list built-in themes
|
|
112
|
+
puppetcam --theme winter # use one
|
|
113
|
+
puppetcam themes --export sprout my-theme.toml # copy the full template
|
|
114
|
+
puppetcam themes --check my-theme.toml # validate your edits
|
|
115
|
+
puppetcam --theme my-theme.toml
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
A theme only needs what it changes. A blue sweater, glasses and your own background:
|
|
119
|
+
|
|
120
|
+
```toml
|
|
121
|
+
name = "Me"
|
|
122
|
+
|
|
123
|
+
[colors]
|
|
124
|
+
sweater = "#3B6FD4"
|
|
125
|
+
|
|
126
|
+
[accessories]
|
|
127
|
+
items = ["glasses"] # sprout, glasses, beanie, headphones
|
|
128
|
+
|
|
129
|
+
[background]
|
|
130
|
+
image = "my-office.jpg" # relative to this file; cropped to fill
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Everything you can set (colors, head roundness and proportions, eye size and spacing, mouth
|
|
134
|
+
width, body width, accessories, background) is listed with comments in
|
|
135
|
+
[`themes/sprout.toml`](src/puppetcam/themes/sprout.toml). Shades like `skin_shade` are derived
|
|
136
|
+
automatically unless you set them. Themes cost nothing at runtime: they're applied once at startup.
|
|
137
|
+
|
|
138
|
+
## How it works
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
webcam ──► sensor thread ─────────────────────► render loop (30 fps) ──► virtual camera
|
|
142
|
+
capture 640x480 mapping + calibration
|
|
143
|
+
MediaPipe Face Landmarker presence: tracking / hold / away
|
|
144
|
+
(52 blendshapes + head pose) idle animator + mic level
|
|
145
|
+
One Euro smoothing
|
|
146
|
+
avatar.render(params)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
1. **Tracking:** [MediaPipe Face Landmarker](https://ai.google.dev/edge/mediapipe/solutions/vision/face_landmarker)
|
|
150
|
+
gives 52 ARKit-style blendshape scores (jaw open, blink, smile...) and the head rotation.
|
|
151
|
+
Pre-trained and used as-is.
|
|
152
|
+
2. **Mapping:** plain arithmetic turns those into 11 normalized parameters (`AvatarParams`),
|
|
153
|
+
relative to your resting face captured at startup.
|
|
154
|
+
3. **Presence:** if your face disappears, the avatar holds its pose for a moment, then fades
|
|
155
|
+
into idle animation with mouth driven by microphone loudness.
|
|
156
|
+
4. **Smoothing:** a [One Euro filter](https://gery.casiez.net/1euro/) removes jitter without adding lag.
|
|
157
|
+
5. **Rendering:** the default avatar is drawn with anti-aliased OpenCV polygons. The 3D effect
|
|
158
|
+
is parallax: features slide, the far eye narrows, ears move the other way, the leaf bounces on a spring.
|
|
159
|
+
|
|
160
|
+
Performance notes and measurements: [docs/optimization.md](docs/optimization.md).
|
|
161
|
+
|
|
162
|
+
## Privacy and honesty
|
|
163
|
+
|
|
164
|
+
- No frames, audio or landmarks are saved or sent anywhere.
|
|
165
|
+
- The **AVATAR badge is on by default**. People in a call deserve to know they are looking at
|
|
166
|
+
an avatar. You can hide it, but please tell them.
|
|
167
|
+
|
|
168
|
+
## Write your own avatar
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from puppetcam.avatars import Avatar
|
|
172
|
+
from puppetcam.params import AvatarParams
|
|
173
|
+
|
|
174
|
+
class MyAvatar(Avatar):
|
|
175
|
+
name = "mine"
|
|
176
|
+
def render(self, p: AvatarParams, dt: float):
|
|
177
|
+
... # return an HxWx3 uint8 BGR image
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Register it from your own package, no fork needed:
|
|
181
|
+
|
|
182
|
+
```toml
|
|
183
|
+
[project.entry-points."puppetcam.avatars"]
|
|
184
|
+
mine = "my_package.avatar:MyAvatar"
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Then `puppetcam --avatar mine`. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
188
|
+
|
|
189
|
+
## Roadmap
|
|
190
|
+
|
|
191
|
+
What's coming next. Priorities follow your feedback: open an
|
|
192
|
+
[issue](https://github.com/cesaredavidepace/puppetcam/issues/new/choose) or a
|
|
193
|
+
[discussion](https://github.com/cesaredavidepace/puppetcam/discussions) to push for something.
|
|
194
|
+
|
|
195
|
+
**v0.1 — now: for people comfortable with a terminal**
|
|
196
|
+
|
|
197
|
+
- [x] Cartoon avatar as a virtual camera for Meet, Teams, Zoom and any other app
|
|
198
|
+
- [x] Away mode, themes, avatar plugins
|
|
199
|
+
- [x] `--sensitivity` for small movements, `puppetcam doctor` to check your setup
|
|
200
|
+
|
|
201
|
+
**v0.2 — no terminal needed**
|
|
202
|
+
|
|
203
|
+
- [ ] Settings saved in a file: theme, camera, sensitivity, badge. No more command-line flags
|
|
204
|
+
- [ ] Menu bar app (macOS) and tray app (Windows): on/off, theme, sensitivity, recalibrate,
|
|
205
|
+
start at login
|
|
206
|
+
- [ ] One-click installers: a signed app for macOS and an installer for Windows, with the face
|
|
207
|
+
model included (no download on first run)
|
|
208
|
+
|
|
209
|
+
**v0.3 — make your own character**
|
|
210
|
+
|
|
211
|
+
- [ ] Draw-your-own avatar from a few PNG layers (head, eyes, mouth shapes), no code needed
|
|
212
|
+
- [ ] More themes and avatars from the community
|
|
213
|
+
|
|
214
|
+
**Later**
|
|
215
|
+
|
|
216
|
+
- [ ] Own virtual camera, so OBS is no longer required (Windows 11 and macOS)
|
|
217
|
+
- [ ] Upper body: shoulders and hands from MediaPipe Pose Landmarker (lite)
|
|
218
|
+
- [ ] "Your photo" avatar: animate a single photo by mesh warping, still CPU-only
|
|
219
|
+
- [ ] Adaptive tracking rate (slow down when you're still, not only when away)
|
|
220
|
+
|
|
221
|
+
## License
|
|
222
|
+
|
|
223
|
+
MIT, see [LICENSE](LICENSE). The face model is downloaded from Google's MediaPipe
|
|
224
|
+
model storage and is not redistributed here; it is covered by its own model card and license.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "puppetcam"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "An animated avatar for your video calls. Runs 100% locally on CPU, no training, no cloud."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.11" # tomllib; high-res time.sleep on Windows
|
|
12
|
+
keywords = ["avatar", "webcam", "virtual camera", "face tracking", "mediapipe", "video calls"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 3 - Alpha",
|
|
15
|
+
"Intended Audience :: End Users/Desktop",
|
|
16
|
+
"Operating System :: Microsoft :: Windows",
|
|
17
|
+
"Operating System :: MacOS",
|
|
18
|
+
"Operating System :: POSIX :: Linux",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Topic :: Multimedia :: Video :: Capture",
|
|
21
|
+
]
|
|
22
|
+
# mediapipe already brings opencv-contrib-python and sounddevice:
|
|
23
|
+
# don't add another OpenCV wheel, two cv2 packages conflict.
|
|
24
|
+
dependencies = [
|
|
25
|
+
"mediapipe>=0.10.14",
|
|
26
|
+
"numpy>=1.24",
|
|
27
|
+
"certifi", # model download on python.org macOS builds, which lack system CAs
|
|
28
|
+
"pyvirtualcam>=0.11",
|
|
29
|
+
"appnope>=0.1.3; sys_platform == 'darwin'",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
dev = ["pytest>=7", "ruff>=0.5", "imageio>=2.30"]
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
puppetcam = "puppetcam.cli:main"
|
|
37
|
+
|
|
38
|
+
[project.entry-points."puppetcam.avatars"]
|
|
39
|
+
sprout = "puppetcam.avatars.sprout:SproutAvatar"
|
|
40
|
+
|
|
41
|
+
[project.urls]
|
|
42
|
+
Homepage = "https://github.com/cesaredavidepace/puppetcam"
|
|
43
|
+
Issues = "https://github.com/cesaredavidepace/puppetcam/issues"
|
|
44
|
+
|
|
45
|
+
[tool.setuptools.packages.find]
|
|
46
|
+
where = ["src"]
|
|
47
|
+
|
|
48
|
+
[tool.setuptools.package-data]
|
|
49
|
+
puppetcam = ["themes/*.toml"]
|
|
50
|
+
|
|
51
|
+
[tool.ruff]
|
|
52
|
+
line-length = 110
|
|
53
|
+
target-version = "py311"
|
|
54
|
+
|
|
55
|
+
[tool.ruff.lint]
|
|
56
|
+
select = ["E", "F", "I", "B", "UP"]
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
testpaths = ["tests"]
|