{"id":22345537,"url":"https://github.com/gerhynes/webcam-fun","last_synced_at":"2025-08-12T00:36:00.924Z","repository":{"id":106048153,"uuid":"108033415","full_name":"gerhynes/webcam-fun","owner":"gerhynes","description":"A page built to practice manipulating data from the webcam. Built for Wes Bos' JavaScript 30 course. ","archived":false,"fork":false,"pushed_at":"2018-01-30T13:00:21.000Z","size":7,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-01-31T11:34:27.319Z","etag":null,"topics":["javascript","javascript30","webcam"],"latest_commit_sha":null,"homepage":"https://gk-hynes.github.io/webcam-fun/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gerhynes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-23T20:05:47.000Z","updated_at":"2018-01-23T22:05:00.000Z","dependencies_parsed_at":null,"dependency_job_id":"b123544c-6948-452a-bfaa-d5af0f41befe","html_url":"https://github.com/gerhynes/webcam-fun","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerhynes%2Fwebcam-fun","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerhynes%2Fwebcam-fun/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerhynes%2Fwebcam-fun/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gerhynes%2Fwebcam-fun/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gerhynes","download_url":"https://codeload.github.com/gerhynes/webcam-fun/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245632415,"owners_count":20647194,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","javascript30","webcam"],"created_at":"2024-12-04T09:18:01.973Z","updated_at":"2025-03-26T10:14:28.479Z","avatar_url":"https://github.com/gerhynes.png","language":"JavaScript","readme":"# Webcam Fun\n\nA page built to practice manipulating data from the webcam. Built for Wes Bos' [JavaScript 30](https://javascript30.com/) course.\n\n[![Screenshot of webcam fun site](https://res.cloudinary.com/gerhynes/image/upload/v1517069521/Screenshot-2018-1-27_Get_User_Media_Code_Along_1_uysoqr.png)](https://gk-hynes.github.io/webcam-fun/)\n\n## Notes\n\n### Getting the video from the webcam\n\nBecause of security restrictions on getting access to a user's webcam, it must be tied to a secure origin (either localhost or a website that is https). For this reason, this project uses browsersync to run a local server.\n\nThe video from the webcam is sent to the video element. By piping it to the canvas element it can be manipulated.\n\nFirst, select the video, canvas, ctx, the strip where screenshots will go, and the sound effect that will accompany them.\n\nMake a function, `getVideo`. Use `navigator.mediaDevices.getUserMedia` and pass it `video`, set to `true`, and `audio`, set to `false`.\n\nThis returns a promise. Call `then` on it and it will give you a `localMediaStream`.\n\nSet the source of the video to be `localMediaStream`.\n\nTo receive a live video feed, it must be from a url, not an object. So use `window.URL.createObjectURL`.\n\nThen call `video.play()`.\n\nIf you inspect the video source, it is a `blob`, i.e. the raw data being piped in off the webcam.\n\nUse `catch` to handle the error caused by someone not allowing you to access their webcam.\n\n```js\nfunction getVideo() {\n  navigator.mediaDevices\n    .getUserMedia({ video: true, audio: false })\n    .then(localMediaStream =\u003e {\n      console.log(localMediaStream);\n      video.src = window.URL.createObjectURL(localMediaStream);\n      video.play();\n    })\n    .catch(err =\u003e {\n      console.error(`OH NO!!!`, err);\n    });\n}\n```\n\n### Painting the video onto the canvas\n\nMake a function, `paintToCanvas`. Get the width and height of the video, and set the width and height of the canvas to be equal to those of the video.\n\nUsing `setInterval`, every 16 milliseconds run `drawImage` on the canvas `ctx` and pass it the video. Start at the top left-hand corner and paint the width and the height.\n\nReturn the `setInterval` so that if you ever need to stop painting you can have access to the interval and call clearInterval on it.\n\n### Taking a photo\n\nMake a function, `takePhoto`.\n\nSet `snap.currentTime` to 0 and run `snap.play` to add the camera shutter sound effect.\n\nListen for an event on the video element called `canplay` (emitted when the video plays) and run `paintToCanvas`.\n\nTo extract the data from the canvas use `canvas.toDataURL` and pass it `\"image/jpeg\"`. This will give you the data in text-based form.\n\nTo get a photo from it, use `document.createElement(\"a\")` and set `link.href` equal to the `data`.\n\nSet the `link`'s attributes to `download` and give it the filename you want the photo to have.\n\nSet the `link`'s `textContent` to \"Download Image\".\n\nFinally, take the `strip` and insert the link node right before the `strip.firstChild` (similar to jQuery's `prepend`).\n\nNow you can download the image.\n\nTo make the image visible on the strip, replace `link.textContent` with `link.innerHTML` and set the `src` to the `data`.\n\n### Manipulate the video with filters\n\nA filter works by getting the pixels from the canvas, changing their rgba values, and putting them back in.\n\nIn `paintToCanvas`, inside the interval, use `ctx.getImageData(0, 0, width, height)` to get the pixels. This will produce a massive array, `pixels.data`.\n\nNow make the filter functions.\n\nMake a function, `redEffect`, pass it in pixels, and loop over every pixel.\n\n`pixels.data[0]` will be the first pixel's red value, `pixels.data[1]` will be its green value, `pixels.data[2]` will be its blue value, `pixels.data[3]` will be its alpha value, and then this will repeat.\n\nOn each loop, increment `i` by 4 and modify the three intervening pixels to change their rgba values. Then return the pixels. This will create a red filter.\n\n```js\nfunction redEffect(pixels) {\n  for (let i = 0; i \u003c pixels.data.length; i += 4) {\n    pixels.data[i + 0] = pixels.data[i + 0] + 100; // red\n    pixels.data[i + 1] = pixels.data[i + 1] - 50; // green\n    pixels.data[i + 2] = pixels.data[i + 2] * 0.5; // blue\n  }\n  return pixels;\n}\n```\n\nNow, make a function, `rgbSplit`. This time set the red value to -150, the green value to +500, and the blue value to -550. This will shift the pixels left or right. If you also set `ctx.globalAlpha` to 0.8 you can get a ghosting effect.\n\n```js\nfunction rgbSplit(pixels) {\n  for (let i = 0; i \u003c pixels.data.length; i += 4) {\n    pixels.data[i - 150] = pixels.data[i + 0]; // red\n    pixels.data[i + 500] = pixels.data[i + 1]; // green\n    pixels.data[i - 550] = pixels.data[i + 2]; // blue\n  }\n  return pixels;\n}\n```\n\nFinally, make a function, `greenScreen`.\n\nCreate an object, `levels`, to store the minimum and maximum green.\n\nSelect the rbg input sliders and set `levels[input.name]` to be their input value.\n\nThen, using a huge `for` loop, check if the red, green, and blue values are between the min and max values, and if they are then remove them.\n\nDo this by setting the fourth pixel value, the alpha, to 0, which makes it totally transparent.\n\n```js\nfunction greenScreen(pixels) {\n  const levels = {};\n\n  document.querySelectorAll(\".rgb input\").forEach(input =\u003e {\n    levels[input.name] = input.value;\n  });\n\n  for (i = 0; i \u003c pixels.data.length; i = i + 4) {\n    red = pixels.data[i + 0];\n    green = pixels.data[i + 1];\n    blue = pixels.data[i + 2];\n    alpha = pixels.data[i + 3];\n\n    if (\n      red \u003e= levels.rmin \u0026\u0026\n      green \u003e= levels.gmin \u0026\u0026\n      blue \u003e= levels.bmin \u0026\u0026\n      red \u003c= levels.rmax \u0026\u0026\n      green \u003c= levels.gmax \u0026\u0026\n      blue \u003c= levels.bmax\n    ) {\n      // If rgb values are between the min and the max take them out\n      pixels.data[i + 3] = 0;\n    }\n  }\n\n  return pixels;\n}\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgerhynes%2Fwebcam-fun","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgerhynes%2Fwebcam-fun","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgerhynes%2Fwebcam-fun/lists"}