This monkey sprite head-tracking page documents a personal pipeline on aogl.cn: turn a short head-turn video into a sprite sheet, calibrate angle-to-frame mapping (not a naive angle/360*frames linear map), and ship a mouse-driven HTML demo with a custom peach cursor. Keywords that match real searches include sprite sheet head turn, CSS background-position animation, interactive character follow mouse, chroma key to WebP.
Pipeline in one sentence
Extract frames, build a contact / calibration sheet to read true facing directions, map compass angles to frame numbers, pack a 10x12 grid (120 frames) into sprite_hd_120.webp, and validate up / right / down / left / diagonals / center in the browser.
calibration_sheet.jpg: contact sheet used to build the angle-to-frame lookup.Front reference frame
The neutral camera-facing still is exported as frame_front.webp for thumbnails and as a sanity check before packing the grid.
frame_front.webp: front pose reference.Live demo: 120-frame HD + peach cursor
Move the mouse around the character: the viewer steps through 120 background positions on sprite_hd_120.webp (10 columns x 12 rows). A peach image follows the pointer with pointer-events: none so clicks still reach the page.
original/monkey2/gemini-code-1778834915677.html uses sprite_hd_120.webp and cursor.png.Sprite sheet assets
Three WebP masters document the iteration: standard density, HD, and the final 120-frame grid used in production.
Source stills (turn_head_1-10)
Ten numbered PNGs sample the rotation arc before packing the full grid, useful for QA and for alt-text-rich galleries.
Source video (MP4)
Two exports document early and refined head-turn passes; chroma was keyed to transparency before sprite packing.
turn_head_v1.mp4turn_head_v2.mp4Generative style anchors
Two Gemini exports in original/monkey2/ sit beside the technical assets for social previews and image search, not replacements for the calibrated sprite.
Offline tooling
Python helpers (gemini-code-1778834954429.py, gemini-code-1778835935559.py, gemini-code-1778835961926.py) and notes in txt.txt record the extraction and chroma rules (preserve subject, avoid eating white/grey). This article keeps the public-facing HTML, images, and video paths stable for SEO.
Calibration sheet vs linear angle math
The mistake that wasted an afternoon was assuming evenly spaced video frames map to evenly spaced compass degrees. Head turns compress near profile views and stretch near three-quarter angles. I printed calibration_sheet.jpg, labeled actual facing every 30°, and built a lookup table in the demo JS. Only after that did diagonals stop “snapping” through the wrong frame. If you reuse this pipeline, treat the sheet as mandatory—not a nice-to-have contact print.
Chroma and WebP packing notes
Version one kept grey studio backdrop pixels; they ate into the WebP alpha and made halos when I scaled the sprite. Version two keyed against green with conservative spill suppression (documented in txt.txt). Packing order is row-major 10×12; the HD grid is heavy (~few MB) so the article uses lazy iframes and still offers sprite.webp for quick comparisons on slow networks.
Peach cursor interaction
The peach PNG is deliberately silly—it proves pointer tracking is live without hiding the character. pointer-events: none on the cursor layer was non-negotiable; without it, mobile taps never reached the page scroll container. I tested eight compass points plus center; any angle that still pointed to frame 0 meant the lookup table needed another row in the sheet.
Relationship to the monkey short article
This sprite rig is a technical spin-off from the same character family as monkey short BTS, but the deliverables differ: here I care about angular fidelity and file size, there I care about story beats. Keeping them as separate URLs stops one page from becoming a grab bag of unrelated MP4s—a pattern AdSense tends to classify as thin even when assets are large.
Frame index math in the demo
Given a 10×12 grid, frame index i maps to column i % 10 and row floor(i / 10). Background position is -col * frameWidth, -row * frameHeight. The lookup table maps compass buckets (N, NE, E, …) to indices—not to degrees—so profile frames get more entries than head-on frames. Documenting that table in txt.txt saved me from re-deriving angles after every re-export.
Memory and network budget
sprite_hd_120.webp is the heaviest asset; I lazy-load the iframe and keep lighter sprite.webp in the gallery for comparison screenshots. On slow networks the demo still paints frame 0 from the front reference while the grid decodes. I avoid loading all three WebP masters inside one iframe—only the 120-frame grid ships in production HTML.
QA script I run before publishing
- Move pointer to eight compass points + center; note frame index in devtools.
- Leave box; confirm custom cursor hides and layers ease to neutral.
- Reload page with cache disabled once after any sprite re-export.
Passing that script is my definition of “done” for this article—not perfect lip-sync or game-ready rigging. I also snapshot the final frame index in a one-line commit message whenever I replace the WebP master so rollback stays obvious.