Canvas, Media & Device APIs
Advanced · 20 min read · ▶ live playground · ✦ checkpoint
Canvas, media, and device APIs are the browser features that let JavaScript draw pixels, control playback, and ask for carefully protected user capabilities. In this lesson you will draw with Canvas 2D live, then learn why camera, clipboard, location, notifications, and sharing are permission-shaped APIs instead of ordinary function calls.
The pattern is bigger than syntax. These APIs touch the user's screen, speakers, files, location, or attention, so good code checks capability, waits for a user gesture when required, and renders a clear fallback when the browser says no.
Canvas is a pixel surface
A <canvas> element is a rectangular bitmap inside the page. JavaScript draws into it through a rendering context:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "#0f766e";
ctx.fillRect(20, 20, 120, 60);The element gives you the surface. getContext("2d") gives you the drawing tool. The 2D context has methods for rectangles, paths, text, images, gradients, transforms, and pixel reading.
Two sizes matter. The width and height attributes set the canvas's internal pixel grid. CSS can make the element appear larger or smaller on the page. For crisp drawings, set the internal canvas size deliberately instead of relying only on CSS.
Canvas is immediate-mode drawing: when you call fillRect, pixels change. If you want the next frame to look different, you usually clear the canvas and draw the whole scene again from state. That should feel familiar from the state-render loop in 17.2; the output target is pixels instead of DOM nodes.
requestAnimationFrame schedules paint-friendly work
requestAnimationFrame(callback) asks the browser to run callback before the next repaint. It is the browser-friendly way to animate because it lines your drawing up with the display instead of guessing with a fixed timer.
The callback receives a timestamp, but beginner animation can ignore that at first and use a frame counter. The important safety rule in examples is to keep the loop controlled. A real animation loop may run until the user leaves the page; a teaching playground should offer Stop or use a hard frame cap.
let frame = 0;
let requestId = null;
function draw() {
frame += 1;
drawScene(frame);
if (frame < 60) {
requestId = requestAnimationFrame(draw);
}
}
requestId = requestAnimationFrame(draw);
// later: cancelAnimationFrame(requestId);Use cancelAnimationFrame(requestId) when the animation should stop. This matches the cleanup habits you already built with timers, event listeners, streams, and observers.
Try it - draw pixels and run a bounded animation
Run the playground. Draw badge paints one still frame. Step frame advances once. Start 24-frame loop uses requestAnimationFrame but stops by itself, and Stop cancels early. The capability table checks API presence without asking for permissions.
This playground uses Canvas live because drawing pixels is local and deterministic. It uses requestAnimationFrame, but the loop has a hard cap and a Stop button. That is the safe pattern: browser-scheduled frames, state-driven drawing, and explicit cancellation.
The capability table is deliberately passive. It checks whether API names exist, but it does not call permission methods. That distinction matters. "This browser has a Geolocation API" is a different claim from "this user granted this page location access."
Audio and video are elements plus promises
For ordinary media playback, the starting point is often HTML:
<video controls src="/intro.mp4"></video>
<audio controls src="/theme.mp3"></audio>The controls attribute lets the browser provide accessible play, pause, scrub, volume, and caption UI. JavaScript can still coordinate playback:
const video = document.querySelector("video");
playButton.addEventListener("click", async () => {
try {
await video.play();
status.textContent = "Playing.";
} catch (error) {
status.textContent = "Playback did not start.";
}
});
pauseButton.addEventListener("click", () => {
video.pause();
});video.play() returns a promise because browsers may block autoplay, require a user gesture, or reject playback for policy reasons. Treat media like fetch from Section 16: assume it can fail and show a visible state.
The deeper audio world is the Web Audio API, starting with AudioContext. It can synthesize, route, analyze, and transform sound. It is powerful, but it is not a casual background-noise button. Browsers commonly require audio to start from a user action, and learners using silent devices should still get honest UI.
Device APIs are permission-shaped
Clipboard, Geolocation, Notifications, and Share look like normal JavaScript APIs, but they sit behind user trust rules.
User gesture means the call is connected to an intentional action such as a click or keypress. Clipboard writes, sharing, media playback, and audio startup often require this. Do not start with code that runs on page load and expects permission-sensitive APIs to work.
Permissions mean the browser may ask the user or use a previously remembered decision. Code must handle yes, no, and unavailable. A denied location request is not a crash; it is a state your UI should render.
Secure context usually means HTTPS or a trusted local development origin. Many device APIs are unavailable on ordinary insecure pages. A sandboxed preview can be even more restricted, so examples should separate capability checks from real permission requests.
Static shapes look like this:
copyButton.addEventListener("click", async () => {
if (!navigator.clipboard) {
showStatus("Clipboard is unavailable in this browser context.");
return;
}
try {
await navigator.clipboard.writeText("Invite code: MIRA-42");
showStatus("Copied.");
} catch (error) {
showStatus("Copy was blocked or denied.");
}
});locationButton.addEventListener("click", () => {
if (!navigator.geolocation) {
showStatus("Location is unavailable.");
return;
}
navigator.geolocation.getCurrentPosition(
(position) => showMap(position.coords),
() => showStatus("Location was denied or unavailable."),
);
});The same design rule applies to Notifications and Share. Check whether the API exists, call it only from a user action, and render success, denial, and unavailable states. Do not hide those branches; they are the honest user experience.
The browser protects the person using it
Canvas asks for no special permission because it draws inside the page you already loaded. Media and device APIs are different because they can reveal private data, make sound, write to the clipboard, interrupt the user, or open a platform share sheet.
That protection is not friction to work around. It is part of the API contract. Good browser code says: "Can I do this here? Did the user ask for it? What should the page show if the answer is no?"
Next, you will look at the other side of rich browser work: keeping expensive JavaScript away from the main thread. Web Workers let a page stay responsive while background code does heavier computation.
Checkpoint
Answer all three to mark this lesson complete