Files
emotes/tools/capture/skin.py
T
selimaj-devandclaude df9a2587e6 Add a tool that measures emotes from a store's 3D preview
tools/capture drives a store page's skin viewer in headless Firefox, stepping its clock one tick at
a time and taking every tick from ten fixed cameras. It then fits our own rig to the frames by
rendering the model (a Python port of LimbBend and PoseApplier) and matching outlines and colours,
and writes the result as Emotecraft JSON. It measures pixels only and never reads the page's
animation data. The README covers the steps, the checks and the limits.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-29 16:55:08 +02:00

30 lines
1.1 KiB
Python

"""Fetches a player's skin texture from Mojang, the same one the store viewer shows for that username.
.venv/bin/python skin.py <username> [out.png]
"""
import base64
import json
import subprocess
import sys
def get(url):
# curl uses the system's certificate store, which python.org's Python doesn't.
return subprocess.run(["curl", "-sSf", url], capture_output=True, check=True).stdout
def fetch(username):
"""Returns (png bytes, slim arms)."""
uuid = json.loads(get(f"https://api.mojang.com/users/profiles/minecraft/{username}"))["id"]
profile = json.loads(get(f"https://sessionserver.mojang.com/session/minecraft/profile/{uuid}"))
prop = next(p for p in profile["properties"] if p["name"] == "textures")
skin = json.loads(base64.b64decode(prop["value"]))["textures"]["SKIN"]
return get(skin["url"]), skin.get("metadata", {}).get("model") == "slim"
if __name__ == "__main__":
png, slim = fetch(sys.argv[1])
out = sys.argv[2] if len(sys.argv) > 2 else f"skins/{sys.argv[1]}.png"
open(out, "wb").write(png)
print(out, "slim" if slim else "wide")