agentsclimarketplace

Virtual avatar engineering

Skill meyverick/agy-skills/skills/virtual-avatar-engineering

Engineers real-time web-based virtual avatars, computer vision pipelines, and high-performance interactive graphics using Svelte 5 and SvelteKit. Orchestrates local ML execution via MediaPipe Tasks Vision, WebAssembly optimization, mathematical animations (LERP, EAR), and Web Worker isolation to drive seamless WebGL/Canvas overlays without dropping frames.From its SKILL.md

Install
npx -y skills add meyverick/agy-skills --skill virtual-avatar-engineering

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its file declares

Copied from the file, not written here

The file declares its own license as Apache-2.0. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

7.8 KB, ~1.8k tokens by cl100k_base, as published. Nobody here has run it

Virtual Avatar Engineering & Real-Time Computer Vision

This skill outlines the process of building high-performance, real-time virtual avatars and computer vision pipelines using Svelte 5 and SvelteKit. It focuses on isolating heavy Machine Learning (ML) inference from the main UI thread, applying mathematical biomechanical calculations, and ensuring stable 60+ FPS broadcast-quality rendering.

Activation Criteria

Use this skill when:

  • Developing web-based VTuber avatars or Face/Hand/Holistic tracking pipelines using MediaPipe.
  • Implementing low-latency device streams (getUserMedia) and processing raw video frames.
  • Integrating 2D (Canvas), 2.5D (Live2D), or 3D (VRM/Three.js) avatars driven by real-time sensor data.
  • Isolating heavy computational workloads using Web Workers and WebAssembly.

1. Computer Vision & WebWorker Isolation

Computer vision inference (like MediaPipe) blocks the main thread, causing severe UI jank and dropped frames in avatar rendering.

  • Worker Isolation: Always execute ML models and computer vision pipelines inside a dedicated Web Worker. The main thread should only handle the Svelte UI and the WebGL/Canvas rendering loop.
  • Zero-Copy Transfers: Use ImageBitmap and postMessage with Transferable Objects to send video frames to the Web Worker without duplicating memory.
  • Execution Delegates: Explicitly configure execution delegates (CPU vs. GPU) depending on the environment. For broadcast setups (e.g., OBS Studio browser sources), CPU delegates often perform better because OBS heavily saturates the GPU.

2. Mathematical Animation & Biomechanics

Raw tracking data from computer vision models is inherently noisy and jittery. It must be smoothed before driving avatar rigs.

  • Linear Interpolation (LERP): Apply LERP to all positional data (x, y, z coordinates) and rotational data (quaternions/Eulers) to smooth out camera micro-jitters.
    // LERP Function
    const lerp = (start, end, amt) => (1 - amt) * start + amt * end;
    
  • Biomechanical Metrics: Compute relational metrics rather than absolute coordinates to handle varying face distances.
    • Eye Aspect Ratio (EAR): Calculate EAR to determine if an eye is open or closed, triggering blink animations.
    • Mouth Open Factor (MOF): Calculate the vertical distance between inner lip landmarks divided by face height to drive the avatar's jaw bone.
  • Geometric Clamping: Clamp tracking metrics to strict upper and lower bounds to prevent avatars from contorting unnaturally when landmarks fail.

3. Svelte 5 Rendering Architecture

Separate the reactive UI state from the 60+ FPS rendering context.

  • Runes Protocol: Use Svelte 5 $state and $derived strictly for UI configurations (e.g., selecting a microphone, toggling debug overlays, changing avatars).
  • Decoupled Rendering: The Canvas or WebGL context (Three.js/PixiJS) must be updated inside a pure requestAnimationFrame loop. Do not bind high-frequency avatar bone transforms directly to Svelte reactive state variables.
  • Immutable Config Sync: When UI configuration changes (e.g., user selects a new accessory), sync the data to the render loop using immutable references to prevent deep-diffing overhead.

4. Device Streams & Defensive Programming

Hardware access is highly volatile. The application must gracefully handle stream failures and permission denials.

  • Permission Handling: Wrap navigator.mediaDevices.getUserMedia in try/catch blocks. Provide clear Svelte UI fallback states if permissions are denied or hardware is missing.
  • Stream Cleanup: If a component unmounts or a user switches cameras, you must explicitly call track.stop() on all MediaStream tracks.
  • WASM Teardown: MediaPipe WASM instances consume significant memory. Ensure the Web Worker receives a teardown message to run .close() on tasks when the avatar session ends.

5. Self-Validation Protocol

Before deploying or committing a virtual avatar component, verify:

  • Thread Safety: Is the MediaPipe inference fully isolated in a Web Worker?
  • Memory Leaks: Does the $effect teardown stop the video stream, cancel the requestAnimationFrame, and terminate the Web Worker?
  • Smoothing: Is raw tracking data being smoothed via LERP or moving averages before being applied to the skeleton?
  • Fallback UI: Is there a reactive Svelte UI state ($state(error)) indicating when a camera is inaccessible or the ML model failed to load?

Reference Example

Below is a conceptual Svelte 5 component demonstrating stream initialization, worker isolation, and decoupled rendering.

<script lang="ts">
	import { onDestroy } from 'svelte';

	let videoElement: HTMLVideoElement;
	let canvasElement: HTMLCanvasElement;
	
	let streamStatus = $state<'loading' | 'active' | 'error'>('loading');
	let errorMessage = $state('');

	let worker: Worker;
	let rAFId: number;
	let mediaStream: MediaStream | null = null;

	// Avatar State (Non-reactive for performance)
	const avatarState = {
		headYaw: 0,
		mouthOpen: 0,
		lerpFactor: 0.2
	};

	$effect(() => {
		// 1. Initialize Web Worker for ML isolation
		worker = new Worker(new URL('./vision-worker.ts', import.meta.url), { type: 'module' });
		
		worker.onmessage = (e) => {
			// Receive raw data, apply LERP smoothing
			const { rawYaw, rawMouth } = e.data;
			avatarState.headYaw = lerp(avatarState.headYaw, rawYaw, avatarState.lerpFactor);
			avatarState.mouthOpen = lerp(avatarState.mouthOpen, rawMouth, avatarState.lerpFactor);
		};

		// 2. Request Camera
		navigator.mediaDevices.getUserMedia({ video: { width: 640, height: 480 }, audio: false })
			.then((stream) => {
				mediaStream = stream;
				videoElement.srcObject = stream;
				videoElement.play();
				streamStatus = 'active';
				
				// 3. Start render loop
				startRenderLoop();
			})
			.catch((err) => {
				streamStatus = 'error';
				errorMessage = err.message;
			});

		// 4. Defensive Cleanup
		return () => {
			if (rAFId) cancelAnimationFrame(rAFId);
			if (worker) worker.terminate();
			if (mediaStream) {
				mediaStream.getTracks().forEach(track => track.stop());
			}
		};
	});

	function startRenderLoop() {
		const ctx = canvasElement.getContext('2d');
		
		const loop = () => {
			if (videoElement.readyState >= 2 && streamStatus === 'active') {
				// Send frame to worker (simplified concept, usually draw to OffscreenCanvas)
				worker.postMessage({ type: 'PROCESS_FRAME' });
				
				// Render Avatar to Canvas based on smoothed avatarState
				ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
				ctx.fillStyle = 'blue'; // Example mouth
				ctx.fillRect(150, 200, 100, avatarState.mouthOpen * 50);
			}
			rAFId = requestAnimationFrame(loop);
		};
		loop();
	}

	const lerp = (start: number, end: number, amt: number) => (1 - amt) * start + amt * end;
</script>

<div class="avatar-container">
	{#if streamStatus === 'loading'}
		<p>Initializing Camera and ML Models...</p>
	{:else if streamStatus === 'error'}
		<p class="error">Camera Error: {errorMessage}</p>
	{/if}

	<!-- Hidden video element for stream source -->
	<video bind:this={videoElement} style="display: none;" playsinline muted></video>
	
	<!-- Avatar Render Target -->
	<canvas bind:this={canvasElement} width="640" height="480"></canvas>
</div>

<style>
	.avatar-container { position: relative; }
	.error { color: red; }
</style>

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Gives 0 of the 12 instructions most performance cost skills give in ~1.8k tokens

Counted across 803 of the 1,058 authors here whose files we hold, read 2026-08-07

  • Keep skill files under 500 lines or tokensin 82 of 803, across 16 files
  • Use imperative form in instructionsin 80 of 803, across 9 files
  • Draft assertions while test runs are in progressin 75 of 803, across 9 files
  • Create two to three realistic test promptsin 74 of 803, across 9 files
  • Write skill descriptions to be pushyin 72 of 803, across 7 files
  • Save test cases to evals JSONin 72 of 803, across 6 files
  • Ask questions about edge cases and input formatsin 72 of 803, across 7 files
  • Save timing data immediately when runs completein 70 of 803, across 5 files
  • Include all trigger conditions in the skill descriptionin 69 of 803, across 3 files
  • Launch all test runs in a single turn or simultaneouslyin 69 of 803, across 3 files
  • Capture intent before writing a skillin 67 of 803, across 1 file
  • Import directly instead of barrel filesin 52 of 803, across 15 files

Said here and by no other author read

  • Execute ML models inside a dedicated Web Worker
  • Use zero-copy transfers for video frames
  • Apply linear interpolation to tracking data
  • Compute relational metrics instead of absolute coordinates
  • Clamp tracking metrics to strict bounds
  • Update canvas inside a requestAnimationFrame loop

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 326,852. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.