MihaiPopa-1/minecraft-skins-1.1m-deduped-64x64-2.0
Minecraft Skins 1.1M Deduped (64x64 Edition) 2.0! Minecraft Skins 1.1M Deduped 1.5 but it's tagged. Format is just a 76.5 MB JSONL file and a 6.1 MB zipped JSONL file (as a JSONZ file) Tools used PIL Image (Python) and Google Colab (T4 GPU tier, but it didn't use the GPU at all!) How it was made Loaded Minecraft Skins 1.1M Deduped 1.5, Tagged using a simple system where it looks for colors and complexity, Output is given in a 6.1 MB ZIP archive or… See the full description on the dataset page: https://huggingface.co/datasets/MihaiPopa-1/minecraft-skins-1.1m-deduped-64x64-2.0.
Minecraft Skins 1.1M Deduped (64x64 Edition) 2.0!
Minecraft Skins 1.1M Deduped 1.5 but it's tagged.
Format is just a 76.5 MB JSONL file and a 6.1 MB zipped JSONL file (as a JSONZ file)
Tools used
PIL Image (Python) and Google Colab (T4 GPU tier, but it didn't use the GPU at all!)
How it was made
- Loaded Minecraft Skins 1.1M Deduped 1.5,
- Tagged using a simple system where it looks for colors and complexity,
- Output is given in a 6.1 MB ZIP archive or a 76.5 MB JSONL.
This can be used to make your own skin generation model (but I'm going with VQ-VAE anyway!)
Future improvements for version 2.5
- Captioning (with Florence 2 Base) or tagging with CLIP
- ~~Filtering troll skins (skins that are formed of just a single color)~~ already done!
Code
Code to reproduce it (first by Claude 4.6 Sonnet):
Same code as before, then:
import numpy as np
from PIL import Image
import json
import os
from tqdm import tqdm
SKIN_DIR = "/content/skins_v1_5"
OUTPUT_FILE = "/content/tags.jsonl"
def get_tags(img):
arr = np.array(img.convert("RGBA"))
rgb = arr[:,:,:3]
alpha = arr[:,:,3]
tags = []
pixels = rgb.reshape(-1, 3)
visible = pixels[alpha.flatten() > 128] # only non-transparent pixels
if len(visible) == 0:
return tags
# --- COLOR TAGS ---
r = visible[:,0].mean()
g = visible[:,1].mean()
b = visible[:,2].mean()
brightness = (r + g + b) / 3
# Dominant color
if brightness < 40:
tags.append("black")
elif brightness > 220:
tags.append("white")
elif r > g + 40 and r > b + 40:
tags.append("red")
elif g > r + 40 and g > b + 40:
tags.append("green")
elif b > r + 40 and b > g + 40:
tags.append("blue")
elif r > 180 and g > 180 and b < 100:
tags.append("yellow")
elif r > 180 and g > 100 and b < 80:
tags.append("orange")
elif r > 150 and b > 150 and g < 100:
tags.append("purple")
elif r > 180 and g < 100 and b > 180:
tags.append("magenta")
elif b > 180 and g > 180 and r < 100:
tags.append("cyan")
elif r > 120 and g > 80 and b < 60:
tags.append("brown")
elif r > 180 and g > 150 and b > 150:
tags.append("pink")
elif abs(r-g) < 20 and abs(g-b) < 20:
tags.append("gray")
# --- BRIGHTNESS TAGS ---
if brightness < 60:
tags.append("dark")
elif brightness > 180:
tags.append("bright")
# --- COMPLEXITY TAGS ---
std = rgb.std()
if std < 10:
tags.append("minimal")
elif std > 60:
tags.append("detailed")
else:
tags.append("colorful")
# --- TRANSPARENCY TAGS ---
transparent_ratio = (alpha.flatten() < 128).sum() / len(alpha.flatten())
if transparent_ratio > 0.3:
tags.append("cape") # lots of transparency = likely has cape/overlay
# --- SKIN TONE TAGS ---
# Check face region (8x8 pixels at 8,8 in skin layout)
face = rgb[8:16, 8:16]
face_r = face[:,:,0].mean()
face_g = face[:,:,1].mean()
face_b = face[:,:,2].mean()
if face_r > 150 and face_g > 100 and face_b < 120:
tags.append("human") # skin-tone face = likely human
return tags
# Load done set for resuming
done = set()
if os.path.exists(OUTPUT_FILE):
with open(OUTPUT_FILE, "r") as f:
for line in f:
try:
entry = json.loads(line)
done.add(entry["filename"])
except:
continue
print(f"Resuming from {len(done):,} already tagged")
skin_files = [
f for f in os.listdir(SKIN_DIR)
if f.endswith(".png") and f not in done
]
print(f"Remaining: {len(skin_files):,}")
with open(OUTPUT_FILE, "a") as f:
for filename in tqdm(skin_files):
try:
img = Image.open(os.path.join(SKIN_DIR, filename))
tags = get_tags(img)
f.write(json.dumps({"filename": filename, "tags": tags}) + "\n")
except Exception:
continue
f.flush()
os.fsync(f.fileno()) # force write to Drive!
print("Done!")then:
!zip -9 tags.jsonl.zip tags.jsonlthen renamed from tags.jsonl.zip to tags.jsonz
