ai-infrastructure-hugg…
Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation,…
Client-side image handling - preview generation, Canvas API resizing, compression, EXIF orientation, format conversion, memory management with object URL cleanup
$ npx -y skills add agents-inc/skills --skill web-files-image-handling --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/web-files-image-handlingContext preview
The summary Claude sees to decide when to auto-load this skill.
Client-side image handling - preview generation, Canvas API resizing, compression, EXIF orientation, format conversion, memory management with object URL cleanup
name: web-files-image-handling description: Client-side image handling - preview generation, Canvas API resizing, compression, EXIF orientation, format conversion, memory management with object URL cleanup
> **Quick Guide:** Two different jobs with two different tools. Displaying an image means > `URL.createObjectURL()` and revoking it afterwards — the browser already applies EXIF rotation, so > rotating manually rotates twice. Processing an image means Canvas: clamp to 4096px, scale in > multiple passes for reductions past 50%, fill white before writing JPEG, and prefer the async > `toBlob()` over `toDataURL()`.
**Detailed Resources:**
---
The two paths disagree about EXIF, which is where most of the bugs are.
unmounted. The browser rotates for you; do nothing about orientation. Start at [examples/core.md](examples/core.md).
rotates for you, so normalise orientation explicitly and never display the result without suppressing the browser's own rotation. Start at [examples/canvas.md](examples/canvas.md).
---
<critical_requirements>
**Revoke every object URL — on unmount, and before creating the replacement.** Each `createObjectURL` pins its blob in memory until revoked, so a picker the user changes their mind in leaks a full image per attempt.
**Decide which path you are on before touching orientation.** Browsers have defaulted to `image-orientation: from-image` since 2020, so normalising for display rotates the image twice; normalise only for bytes that leave the browser.
**Clamp canvas dimensions to 4096px.** Past that the canvas fails silently or takes the tab down, and the limit is lower again on mobile.
**Scale in multiple passes when reducing by more than half.** One-pass downsampling undersamples and produces a soft, aliased result; two intermediate steps keep it sharp.
</critical_requirements>
---
**Auto-detection:** URL.createObjectURL, URL.revokeObjectURL, createImageBitmap, OffscreenCanvas, canvas.toBlob, canvas.toDataURL, convertToBlob, ctx.drawImage, imageSmoothingQuality, image-orientation, EXIF orientation, 0x0112, FileReader.readAsDataURL, naturalWidth, image/webp, step-down scaling, thumbnail generation, client-side resize, image crop
**Applies to:**
**Handled elsewhere:**
rather than raw Canvas calls
---
<philosophy>
Preview and processing pull in opposite directions, and conflating them is the source of most image bugs.
A preview should cost nothing: `URL.createObjectURL()` hands `<img>` a reference to bytes that are already in memory, with no decode into JavaScript and no copy. The price is manual lifetime management — the reference outlives the component unless revoked.
Processing is the opposite: the pixels have to be decoded into a canvas, transformed, and encoded back out. Everything expensive lives here, which is why the canvas work is worth doing once, at the size you actually need, rather than repeatedly at full resolution.
The browser's own EXIF handling sits across the seam. It rotates for display and not for canvas, so the same file has two orientations depending on which path read it.
</philosophy>
---
<patterns>
Revoke the previous URL before creating the next one, and revoke on unmount. Creating a URL during render leaks one per render.
useEffect(() => {
const url = URL.createObjectURL(file);
setPreviewUrl(url);
return () => URL.revokeObjectURL(url);
}, [file]);Full code: [examples/core.md](examples/core.md)
Clamp to the browser limit, keep the aspect ratio, ask for high-quality smoothing, and fill white before drawing when the output is JPEG — JPEG has no alpha channel, so transparency encodes as black.
const MAX_CANVAS_DIMENSION = 4096;
const ratio = Math.min(maxWidth / img.width, maxHeight / img.height);
const width = Math.round(img.width * Math.min(ratio, 1)); // never upscale
const height = Math.round(img.height * Math.min(ratio, 1));
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = "high";
if (mimeType === "image/jpeg") {
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, width, height);
}
ctx.drawImage(img, 0, 0, width, height);Full code: [examples/canvas.md](examples/canvas.md)
`drawImage` samples a fixed neighbourhood, so a large reduction in one pass throws away most of the source. Halving repeatedly keeps every pixel contributing.
const STEP_DOWN_THRESHOLD = 0.5;
if (targetWidth / img.width < STEP_DOWN_THRESHOLD) {
// 4000 → 400 → 100 rather than 4000 → 100
cThe official skills marketplace for Agents Inc. 150+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?
Repo: agents-inc/skills
Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation,…
LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production…
Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns
Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and…
Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training
Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation,…