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.
Files changed (39) hide show
  1. puppetcam-0.1.0/LICENSE +21 -0
  2. puppetcam-0.1.0/PKG-INFO +253 -0
  3. puppetcam-0.1.0/README.md +224 -0
  4. puppetcam-0.1.0/pyproject.toml +59 -0
  5. puppetcam-0.1.0/setup.cfg +4 -0
  6. puppetcam-0.1.0/src/puppetcam/__init__.py +3 -0
  7. puppetcam-0.1.0/src/puppetcam/__main__.py +3 -0
  8. puppetcam-0.1.0/src/puppetcam/app.py +124 -0
  9. puppetcam-0.1.0/src/puppetcam/audio.py +70 -0
  10. puppetcam-0.1.0/src/puppetcam/avatars/__init__.py +3 -0
  11. puppetcam-0.1.0/src/puppetcam/avatars/base.py +62 -0
  12. puppetcam-0.1.0/src/puppetcam/avatars/sprout.py +278 -0
  13. puppetcam-0.1.0/src/puppetcam/capture.py +122 -0
  14. puppetcam-0.1.0/src/puppetcam/cli.py +199 -0
  15. puppetcam-0.1.0/src/puppetcam/doctor.py +96 -0
  16. puppetcam-0.1.0/src/puppetcam/engine.py +85 -0
  17. puppetcam-0.1.0/src/puppetcam/filters.py +74 -0
  18. puppetcam-0.1.0/src/puppetcam/idle.py +58 -0
  19. puppetcam-0.1.0/src/puppetcam/mapping.py +163 -0
  20. puppetcam-0.1.0/src/puppetcam/params.py +54 -0
  21. puppetcam-0.1.0/src/puppetcam/platform_tweaks.py +76 -0
  22. puppetcam-0.1.0/src/puppetcam/presence.py +44 -0
  23. puppetcam-0.1.0/src/puppetcam/sinks.py +88 -0
  24. puppetcam-0.1.0/src/puppetcam/themes/alien.toml +21 -0
  25. puppetcam-0.1.0/src/puppetcam/themes/mint.toml +16 -0
  26. puppetcam-0.1.0/src/puppetcam/themes/office.toml +15 -0
  27. puppetcam-0.1.0/src/puppetcam/themes/sprout.toml +43 -0
  28. puppetcam-0.1.0/src/puppetcam/themes/winter.toml +13 -0
  29. puppetcam-0.1.0/src/puppetcam/themes.py +178 -0
  30. puppetcam-0.1.0/src/puppetcam/tools.py +115 -0
  31. puppetcam-0.1.0/src/puppetcam/tracker.py +188 -0
  32. puppetcam-0.1.0/src/puppetcam.egg-info/PKG-INFO +253 -0
  33. puppetcam-0.1.0/src/puppetcam.egg-info/SOURCES.txt +37 -0
  34. puppetcam-0.1.0/src/puppetcam.egg-info/dependency_links.txt +1 -0
  35. puppetcam-0.1.0/src/puppetcam.egg-info/entry_points.txt +5 -0
  36. puppetcam-0.1.0/src/puppetcam.egg-info/requires.txt +12 -0
  37. puppetcam-0.1.0/src/puppetcam.egg-info/top_level.txt +1 -0
  38. puppetcam-0.1.0/tests/test_core.py +178 -0
  39. puppetcam-0.1.0/tests/test_themes_platform.py +138 -0
@@ -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.
@@ -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
+ ![demo](docs/demo.gif)
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
+ ![themes](docs/themes.png)
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
+ ![demo](docs/demo.gif)
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
+ ![themes](docs/themes.png)
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"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """puppetcam: an animated avatar for your video calls, running 100% locally."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ main()