mcpField
A
avatar

avatar

github.com/raphaelsalajaOther460 installsUpdated today
Repository

About avatar

avatar is a design and implementation skill for turning an object into an animated character. It specifies how to measure references, draw a silhouette and spherical eyes, build motion and moods, and verify the result.

Key features

  1. 01Reference-frame measurement
  2. 02Flat silhouette and projected eyes
  3. 03Continuous gaze, blink, and body motion
  4. 04Number-based mood transitions
  5. 05Page-triggered reactions
  6. 06Reduced-motion and offscreen handling

Use cases

  1. 01Creating an animated character from an object
  2. 02Reproducing a named character from reference footage
  3. 03Checking mood and interaction animations
  4. 04Auditing motion, accessibility, and frame behavior

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/raphaelsalaja/skills --skill avatar

After installing, type/avatarin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

face.js
sheet.js
agents/
openai.yaml

Details

From the project README

Avatar

This skill turns an object into a small living character. It draws one flat silhouette with two capsule eyes, then drives the whole body from one loop so it glances, blinks, breathes and reacts.

Measured eyes, a body that is never still

The gaze, eye and blink values in face.js are measured off reference footage and are exact. The moods past idle are tuned starting points. A character whose eyes move while its body holds still is a finding.

Gathering references belongs to gather. Taking a reference animation apart frame by frame belongs to deconstruct. Offering silhouette variants belongs to prototype. Interface motion and its 300ms budget belong to motion, not a character's body. Frame cost belongs to frames. Opening the result belongs to verify.

1. Study the reference

When the user names a reference character, open its source and step its recording at 10fps. Measure eye size, tilt, spacing and blink timing off the frames. A character drawn from one glance at the reference is avatar-measure-the-reference.

Keep measured values as measured. Rounding a 15.5° eye spacing to 15° or a 180ms blink to 200ms is avatar-keep-the-measurements. With no reference named, start from face.js.

2. Draw the silhouette

Reduce the object to one flat, solid shape in one saturated colour. Keep only the part that names it, such as a handle, a lid or a stem. An outline, shading, a mouth or a nose is avatar-flat-silhouette.

It reads at its shipped size, usually 28–40px. Draw it on a small grid, such as a 14 by 17 viewBox, and crop the viewBox tight to the ink. A part that moves on its own, like a lid, gets its own path.

Colour comes from two variables, --avatar-body and --avatar-eyes, checked in both themes. A fill written into the path is avatar-colour-variables.

3. Put the eyes on a sphere

Two white capsules, each about 2.2 times as tall as wide, rest high and to the right. They lean like a backslash, with the head tilted about 12°.

The eyes sit on a sphere behind the face. A yaw, pitch and roll place them, so they narrow near the edge and fade as they turn behind. Eyes sliding flat across the face is avatar-eyes-on-a-sphere. drawEyes in face.js does the projection.

Clip both eyes to the silhouette path, inside the group that moves the body. An eye drawn past the outline is avatar-clip-to-the-body.

4. Give the whole body life

Nothing holds still. The gaze drifts on layered sine waves and glances to a new spot every 1.5–4s, and big glances bring a blink. A gaze parked at rest between events is avatar-never-still.

Blinks take 180ms and close in the first 45% of it. They land 1.9–4.6s apart, and 18% are doubles. A blink on a fixed interval is avatar-irregular-blinks.

The body breathes 1.2% on a 3.4s cycle, floats slightly and leans toward its gaze a beat late. Eyes settle in about 60ms and the body in 220ms. Eyes moving inside a frozen body is avatar-whole-body.

5. Make moods from eye shapes

A mood is one row of numbers: eye width, height, tilt, spacing, openness and a gaze offset. Moods blend over about 90ms on an exponential ease-out and never overshoot. A separate drawing swapped in per mood is avatar-moods-as-numbers.

Start from idle, attentive, excited, happy, sleepy and asleep. Add one or two moves only this object can make, such as a lid that lags behind a hop. A character with no move of its own is avatar-object-move.

6. Wire the reactions

Each reaction answers one input from the page:

  • The pointer enters after 6s away. The eyes spin 360° round the back over 1.1s, then follow the pointer.
  • The pointer rests on the primary action. The eyes widen and the body bounces slightly.
  • The user presses the action or the character. It hops for 750ms with squash and stretch, then squints happily back out.
  • Nothing happens for 24s. It grows sleepy, falls asleep at 30s with slow deep breaths and wakes with a spin.

Clamp the followed gaze to ±45° of yaw so the eyes stay on the face, and ignore touch pointers for following. A character that ignores the page around it is avatar-react-to-the-page.

When the character is the main toy on its page, it may also react to distance. It turns curious inside 640px, wary inside 260px and recoils inside 100px. A poked eye shuts while the other stays open.

7. Run it from one loop

One requestAnimationFrame loop steps createAvatar from face.js and writes SVG attributes through refs. The step caps at 64ms so a returning tab does not jump. Per-frame state updates belong to frames.

Run the loop only while the character is on screen, through an IntersectionObserver. A loop that keeps running offscreen is avatar-pause-offscreen.

Render the resting pose on the server from restingEyes, so the first paint already has eyes. A face that pops in on hydration is avatar-render-the-rest.

Under prefers-reduced-motion: reduce, the character holds its resting pose and starts no loop. A character that still glances and hops is avatar-still-when-reduced. The character is decorative, so its SVG takes aria-hidden="true".

8. Prove it on a contact sheet

A single screenshot cannot show motion, and a hidden tab throttles the loop. Run sheet.js through the browser's evaluate call, then call window.__avatarSheet.start({ selector }).

Drive each mood with pointer events: idle, enter, hover, press and leave. Call window.__avatarSheet.stop() and screenshot the sheet it lays out. One still frame offered as proof is avatar-contact-sheet.

A warning in the result means the tab was hidden or the loop stalled, so frames repeat or gaps widen. Keep the tab visible and sample again. Sleep needs 30s without input, so sample it once on its own.

Finish with the character at its shipped size in both themes, then call window.__avatarSheet.clear().

The pair

Every check is a pair. The broken line sits beside the line that replaces it.

RuleBrokenReplacement
avatar-measure-the-referenceEyes placed from one look at the referenceSize, tilt, spacing and blinks measured off frames at 10fps
avatar-keep-the-measurementssplit: 15, rounded to look tidysplit: 15.5, as measured
avatar-flat-silhouetteA cup with an outline, shading and a smileOne solid shape and two eyes
avatar-colour-variablesfill="#c27a3e" in the pathfill="var(--avatar-body)", set per theme
avatar-eyes-on-a-spheretranslate(dx, dy) on both eyesdrawEyes(face, gaze, lid, head) from yaw, pitch and roll
avatar-clip-to-the-bodyAn eye hanging past the outline on a wide glanceEyes inside a clipPath of the body path
avatar-never-stillEyes parked at rest between blinksLayered drift and a glance every 1.5–4s
avatar-irregular-blinksanimation: blink 5s infinite180ms blinks 1.9–4.6s apart, 18% doubles
avatar-whole-bodyOnly the eyes moveThe body breathes, floats and leans 220ms behind the gaze
avatar-moods-as-numbers{happy ? <HappyFace /> : <Face />}happy: { eyes: pair(0.522, 0.217, 18) }, blended over 90ms
avatar-object-moveA cup that moves like any blobThe lid lifting a beat behind the hop
avatar-react-to-the-pageOne idle loop whatever the pointer doesSpin on enter, follow, widen on hover, hop on press, sleep when left
avatar-pause-offscreenA loop running below the foldThe loop started and stopped by an IntersectionObserver
avatar-render-the-restEyes appearing after hydrationrestingEyes(head) in the server HTML
avatar-still-when-reducedGlancing and hopping under reduced motionThe resting pose and no loop
avatar-contact-sheetOne screenshot of the idle poseA sheet.js sheet through every mood, then shipped size in both themes

Reporting

Severity. HIGH is a body that never moves, eyes escaping the silhouette or motion under reduced motion. MEDIUM is flat sliding eyes, a fixed blink, swapped mood drawings, an offscreen loop, a missing reaction or proof from one screenshot. LOW is a rounded measurement, a fill in the path, a rest pose that pops in or a character with no move of its own.

Format. One finding per root cause:

file:line - [rule-id] what is wrong

Then a Rule | Count | Severity summary. Block when any HIGH remains, Approve otherwise. Mark a reference you could not open or step through as Not verified.

Comments

Markdown supported