Library / SDK
gazijarin/itsgiving avatar
gazijarin/itsgiving

gazijarin/itsgiving: a webcam meme overlay for meetings

Express yourself in meetings (with memes, of course).

865 stars106 forksPythonMIT

At a glance

What is it?
Itsgiving maps fourteen hand and face poses to meme images and publishes the result through a virtual camera, so Zoom and Meet see the joke instead of your face. The setup is small; the dependency pins and the pose tuning are not.
Who is it for?
Adopt itsgiving if you run Python 3.11 or 3.12 on macOS, Windows or Linux, can install a virtual camera backend, and want a pose-triggered meme overlay you can extend by dropping files into assets/. Do not adopt it if you cannot accept the pinned dependency set or if you need the reactions to be deterministic in front of people who did not opt in.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 12 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 16, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What itsgiving is for

A video call gives you one channel: your face. Itsgiving adds a second one. You pull a pose at the webcam, the program decides which pose it is, and it composites a matching image over your head, scaled to your face and tracking you around the frame. Point a meeting app at the virtual camera and the other participants see the composite rather than the raw feed.

The audience is narrow and specific. You need to be on a call where a meme overlay is welcome, you need a webcam, and you need to be willing to install a virtual camera backend before the meeting app will see anything. The README is direct about the social risk: the overlay fires on its own, everyone sees whatever it decides, and the author suggests trying it on a call with someone who likes you first. That is not a disclaimer bolted on at the end. It is the central constraint of the tool.

Fourteen reactions ship: time out, heart hands, hands over face, crashing out, dancing, nose pinch, flirty, hand up, tongue out, gasp, disgust, talking to the wall, side-eye, and spinning. Each one has a defined pose in the README's table, and each one maps to a file in assets/ named after the pose.

The pipeline: MediaPipe, face-relative geometry, and one ordered pass

The README lays out five stages. A camera frame goes into MediaPipe, which returns 478 face landmarks plus 52 blendshapes, two hands of 21 points each, and body points for shoulders, elbows and wrists. A measurement stage converts that into face-relative geometry, tongue colour and hand speed. A baseline stage re-expresses facial expressions in sigma above your own neutral face. Then decide() runs a single ordered pass, and the first pose that matches wins. An arm and hold stage requires a pose to persist for N frames before it fires, and lets it linger for 10 frames after.

The normalisation is the interesting engineering decision. Landmarks arrive as pixel coordinates, which change with how far you sit from the lens, so nothing is compared in pixels. Every distance is divided by the width of the face box. The README's example, near(hand.index, face.mouth, 0.22), means within 22 percent of a face width, and the documentation states that this reads the same at 40 cm and at a metre and a half. Hand speed gets the same treatment: face-widths per frame.

That ordering rule has a consequence the README calls out twice. POSES is checked top to bottom and the first match wins, so a new pose must sit above anything it might be mistaken for. If a pose never fires, the README says to check POSES order before touching a threshold, because lowering Z cannot fix an earlier match.

Installing itsgiving and running the first calibration

The repository targets Python 3.11 or 3.12. The README's setup sequence creates a virtual environment, activates it, and installs the pinned requirements. Three MediaPipe models, around 15 MB in total, download themselves on first run.

bash
python3.12 -m venv venv
source venv/bin/activate           # Windows: venv\Scripts\activate
pip install -r requirements.txt

After activation you are inside the venv; after pip finishes, requirements.txt should have resolved mediapipe==0.10.21, numpy<2, opencv-python<5, opencv-contrib-python<5, protobuf>=4.25.3,<5, pyvirtualcam and pillow. If pip proposes OpenCV 5 or NumPy 2, stop: the pins exist to prevent exactly that, and the file's own comment says unpinning one means unpinning all three.

The second file, its_giving_v2.py, calibrates the expression thresholds to your face rather than to a guessed number. Run it once, then run it for real.

bash
python its_giving_v2.py --calibrate   # once, seven seconds
python its_giving_v2.py

A preview window opens with a HUD. Press d to toggle the HUD, c to recalibrate, q to quit, and the number and symbol keys to force a reaction on screen for two seconds. To check a swapped asset, press that pose's test key and watch where it sits on your head.

For the virtual camera, the README gives one backend per platform: install OBS Studio on macOS and open it once, install OBS Studio or its virtual-camera installer on Windows, and on Linux run sudo apt install v4l2loopback-dkms followed by sudo modprobe v4l2loopback. When the program starts it prints the device it publishes to, for example Virtual camera: 'OBS Virtual Camera', and that is the camera you select in Zoom, Meet, Teams or Discord. Start itsgiving before the meeting app, because the README notes that most of them scan for cameras once at launch.

The dependency pins are the install

Most of the setup risk in this project lives in requirements.txt, and the file says so in its own comments. MediaPipe 0.10.30 and later, including 1.0.x, ship macOS wheels that abort on startup with a service-unavailable check failure or a MetalHelper crash, so mediapipe is held at 0.10.21. That build needs numpy<2, while OpenCV 5 needs numpy>=2. MediaPipe 0.10.21 also asks for an unpinned opencv-contrib-python, which is what quietly pulls OpenCV 5, then NumPy 2, then a broken install. The explicit opencv-python<5 and opencv-contrib-python<5 pins are the only thing standing between you and that chain.

Nothing in the reaction code cares about the OpenCV version. The pins are there for resolution, not for features. That makes them easy to remove by accident and hard to justify to a reader who just wants a newer OpenCV. The README's instruction is blunt: do not unpin the dependencies.

The verified configuration named in the file is Python 3.12 on macOS arm64. The README states Python 3.11 or 3.12 generally, and gives platform-specific virtual camera instructions, but it does not claim a verified matrix beyond that one line. If you are on Windows or Linux, you are following the README's steps without the same stated verification.

Adding a pose, and where that goes wrong

Extending the reaction set is a four-step edit. Drop the image into assets/ named after the pose, add the name to POSES above anything it could be confused with, add a branch to decide(), and give the pose an ARM count if it is twitchy. The README supplies the shape of a decide() branch and lists what is in scope: face with .nose, .chin, .mouth, .w, .h and .b("jawOpen") for any blendshape; hands with .palm, .thumb, .index and .open; body with .elbows_up; m for expressions in sigma; and near(a, b, k) for within k face widths.

python
    for h in hands:
        if near(h.palm, face.chin, 0.5) and not h.open:
            return "thinking", d

The README is honest that the hard part is not triggering. Getting a pose to fire is easy; the work is stopping it from firing during everything nearby that might be confused with it, and watching the number stay low in the HUD. If a pose needs an expression channel that is not measured yet, you add it to Z, FLOOR and measure(), then surface it in draw_hud(), because you cannot tune a number you cannot see.

Two failure modes are documented. TEST_KEYS holds one key per pose matched by position, so adding a fifteenth pose is fine but it gets no test key, while removing a pose without removing its key crashes when that key is pressed. Separately, a new pose that never fires is almost always losing to an earlier match in POSES, not to a threshold.

Assets, the missing-file path, and what is not documented

Assets live in assets/ and are named after the pose: heart.jpeg, spin.gif. Swapping one is a file drop. JPEG, PNG and animated GIF all work, alpha channels composite properly, and GIF frame timings are read from the file rather than assumed. A prefix ending in an underscore is ignored, so 2019_heart.jpeg still counts as the heart reaction. When an asset is missing you get a red placeholder rather than a crash, which is the right default for something running live in a meeting.

The repository also contains calibration.json, which is where the v2 calibration writes the thresholds it learned from your face. The README does not document its schema, does not say whether it is safe to edit by hand, and does not describe what happens if you run the calibrated script on a different machine or a different camera. The --calibrate flag is described as a once-only seven-second step, but the README does not document rollback if a calibration goes badly; pressing c to recalibrate is the only recovery path it names.

There are no releases retrieved for this repository, so there is no version to pin against and no changelog to read. The last push was on 2026-09-08, which is recent, but the absence of tagged releases means an upgrade is a pull of the main branch and a re-read of the README.

Alternatives and the wrong-tool cases

The closest alternative is OBS Studio itself. OBS is already the recommended backend for the virtual camera on macOS and Windows, and it can composite an image over a webcam feed with a scene, a source and a filter. The difference is the trigger. OBS composites whatever you configure, continuously, and you switch scenes by hand or by hotkey. Itsgiving decides for you: MediaPipe reads the pose and the first match in an ordered list wins, with an arm-and-hold stage to stop it flickering. If you want a permanent overlay that never surprises you, OBS alone is the better tool. If you want the overlay to react to what you do with your hands, itsgiving is doing something OBS does not do out of the box.

The wrong-tool cases are clear enough. Do not run it on a call where the participants have not agreed to it; the README's own advice is to test with someone who likes you first. Do not use it where a mis-fired reaction has consequences, because decide() is a heuristic over landmarks and blendshapes, not a classifier with a confidence you can threshold at the call level. Do not use it on a machine where you cannot install a virtual camera backend, because the preview-only mode (python its_giving.py --no-vcam) never reaches the other participants. And do not use it if you need a supported dependency matrix: the mediapipe pin is load-bearing and the README says so.

Licence and upgrade cost

The repository is MIT licensed, with a LICENSE file at the top level. In practical terms that permits commercial use, modification and redistribution provided the copyright notice and permission notice are included; it also disclaims warranty. That is a summary of the licence, not legal advice, and if you are redistributing the memes in assets/ rather than the code, the licence on the code tells you nothing about the images.

The upgrade cost is dominated by the pins. Because mediapipe is held at 0.10.21 for a macOS startup abort in later wheels, moving forward means one of two things: waiting for a MediaPipe build that opens a detector on macOS without aborting, or moving to a platform where the newer wheels work. Until then, an upgrade of any single dependency in the chain is an all-three upgrade, and the README treats that as a known hazard rather than a temporary annoyance. With no releases to diff against, you also have no changelog to tell you what changed between the version you pulled and the version you are pulling now.

Editorial conclusion

Adopt itsgiving if you run Python 3.11 or 3.12 on macOS, Windows or Linux, can install a virtual camera backend, and want a pose-triggered meme overlay you can extend by dropping files into assets/. Do not adopt it if you cannot accept the pinned dependency set or if you need the reactions to be deterministic in front of people who did not opt in. Before your first call, verify three things: that pip install -r requirements.txt completes without pulling OpenCV 5 or NumPy 2, that the virtual camera device prints on startup and appears in your meeting app's camera list, and that a test key fires the pose you expect against the HUD. The repository's last push was on 2026-09-08 and no releases were retrieved, so treat the main branch as the only version there is.

Frequently asked questions

How do I install itsgiving?

Create a Python 3.11 or 3.12 virtual environment, activate it, and run pip install -r requirements.txt. Three MediaPipe models of about 15 MB download themselves on first run. Do not unpin the dependencies, because the mediapipe, NumPy and OpenCV pins hold each other in place.

How do I use itsgiving in a Zoom or Meet call?

Install a virtual camera backend first: OBS Studio on macOS and Windows, or v4l2loopback-dkms on Linux. Start itsgiving before the meeting app, then select the device it prints on startup, such as OBS Virtual Camera, in the app's camera setting.

What is the difference between its_giving.py and its_giving_v2.py?

The README describes the second file as the same thing with the expression thresholds calibrated to your face instead of to a guessed number. You run its_giving_v2.py --calibrate once for seven seconds, and the results are stored in calibration.json.

Can I add my own memes to itsgiving?

Yes. Drop a file into assets/ named after the pose, for example heart.png to replace the heart reaction. JPEG, PNG and animated GIF all work, transparency composites properly, GIF timings are read from the file, and a missing asset produces a red placeholder rather than a crash.

Official sources

  1. gazijarin/itsgiving on GitHub
  2. Issues
  3. License: MIT
  4. README
Community notes

Community notes