Make a mask
A mask is a small self-contained web page. MEETAMASK runs it offscreen, draws your webcam and your effect, and streams the result into Zoom, Meet or Teams. Imported masks are other people’s code — so every one runs in a locked sandbox: no disk, no network, no windows. Here’s exactly what that allows.
What we accept
Accepted
- ✓A .zip or a folder containing
index.html— at the root, or one level down. - ✓Fully self-contained — every script, style, image, font and model lives inside the package.
- ✓≤ 200 MB.
- ✓Draws to fill 1920×1080 (16:9).
Won’t work — the sandbox blocks it
- ✕No network of any kind. No
fetchto the internet, no<script src="https://…">, no CDN, fonts or APIs. MediaPipe / Three.js from a CDN will not load — bundle them. - ✕No
fetch/ XHR even for your own files, and no ES modules (import,type="module") — blocked on local pages. - ✕No reading anything outside your folder — zero access to the user’s files.
- ✕No new windows / navigation, no downloads, no audio (video-only, muted).
What you can use
Everything a normal in-page script can do, minus the network. The camera is handed to you automatically.
APIs
- ✓Canvas 2D & WebGL,
requestAnimationFrame, all in-page JS. - ✓The webcam:
getUserMedia({ video:true })— we give you the real camera. Draw its frames to canvas and paint on top. - ✓Output is not mirrored — the meeting app mirrors your self-view for you.
Loading code & assets
- ✓Local files via tags:
<script src="./app.js">,<img src="./x.png">,<link href="./s.css">. - ✓Use UMD / classic library builds (a global like
THREE), not the ESM build. - ✓Embed data as
data:orblob:URIs (base64 a model or image into your JS). - ✓Auto-start: include
<button id="startBtn">— we click it for you. (Or start on load.)
Minimal skeleton
A complete, valid mask: it shows your camera with a start button. Add your effect inside the loop.
<!-- index.html — the whole mask --> <!doctype html><html><head><meta charset="utf-8"> <style>html,body{margin:0;background:#000;overflow:hidden}#c{width:100%;height:100%}</style> </head><body> <video id="v" autoplay playsinline muted style="display:none"></video> <canvas id="c" width="1920" height="1080"></canvas> <button id="startBtn">Enter</button> <script> const v = document.getElementById('v'); const x = document.getElementById('c').getContext('2d'); async function start() { document.getElementById('startBtn').style.display = 'none'; v.srcObject = await navigator.mediaDevices.getUserMedia({ video: { width: 1920, height: 1080 } }); (function loop(){ x.drawImage(v, 0, 0, 1920, 1080); /* …your effect here… */ requestAnimationFrame(loop); })(); } document.getElementById('startBtn').addEventListener('click', start); </script> </body></html>
Let Claude build it
No code? Copy this prompt, paste it into Claude (or any AI), describe the effect you want — it hands back a ready-to-import index.html with every sandbox rule baked in.
Loading…
Checklist
index.htmlpresent (root, or one folder down)- Zero
https:/// CDN references — all local - No
fetch/import— tags + inline only - Fills 1920×1080
- Has
#startBtnor auto-starts - Under 200 MB
Drop it in.
In MEETAMASK, open Add mask in the gallery and pick your .zip or folder. It shows up as yours and goes live on your next call.