A client-side mod that loads player skins and capes by username from an HTTP source you control — HD textures, animated GIF/APNG, one shared engine across Minecraft 1.7.10 through 1.21.1.
If none of your configured sources return anything for a player, their vanilla skin is left untouched. There is no Mojang or third-party fallback baked in; the mod only ever shows what your sources hand it.
| Minecraft | Loaders | Artifact(s) |
|---|---|---|
| 1.7.10 | Forge | skinsandcapes-mc1.7.10 |
| 1.12.2 | Forge | skinsandcapes-mc1.12.2 |
| 1.19.2 | Forge, Fabric | skinsandcapes-mc1.19, skinsandcapes-fabric-1.19.2 |
| 1.20.1 | Forge, NeoForge, Fabric | skinsandcapes-mc1.20.1¹, skinsandcapes-fabric-1.20.1 |
| 1.21.1 | NeoForge, Fabric | skinsandcapes-mc1.21.1, skinsandcapes-fabric-1.21.1 |
¹ The 1.20.1 Forge jar also loads on NeoForge 1.20.1.
Client-side only — nothing needs to be installed on the server.
- Grab the jar for your Minecraft version and loader from Releases and drop it into
mods/. - Add its runtime dependency, if it has one:
- 1.7.10 — UniMixins
- 1.12.2 — MixinBooter
- Fabric builds — Fabric API
- Forge 1.19/1.20.1 and NeoForge 1.21.1 need nothing extra.
- Launch the game once. The mod writes a disabled config to
config/skinsandcapes.json; edit it (see below) to point at your source.
Everything lives in config/skinsandcapes.json. loadlist starts empty, which means the mod changes nothing. Add one or more sources to turn it on. Edits are re-read while the game is running — no restart needed.
Any URL may contain {nickname}, {uuid}, or {uuid_dashed}.
Point straight at the finished texture:
{
"enableSkin": true,
"enableCape": true,
"enableAnimation": true,
"hdMaxResolution": 512,
"loadlist": [
{
"name": "my-cdn",
"type": "direct",
"priority": 100,
"skin": "https://example.com/skins/{nickname}.png",
"cape": "https://example.com/capes/{nickname}.png",
"model": "auto"
}
]
}model is auto (detect slim vs. wide from the texture), slim, or wide.
Point at an endpoint that tells the mod where the textures are. format is json, text, or redirect:
{
"name": "my-api",
"type": "api",
"priority": 200,
"url": "https://example.com/api/{uuid}",
"format": "json",
"json": { "skin": "textures.skin.url", "cape": "textures.cape.url", "model": "textures.skin.model" }
}With more than one source, they are tried from the lowest priority value upward and the first that returns a texture wins.
| Key | Default | Meaning |
|---|---|---|
enableSkin / enableCape |
true |
Whether to override skins / capes at all. |
enableAnimation |
true |
Play animated GIF/APNG; when off, only the first frame is shown. |
hdMaxResolution |
512 |
Textures larger than this (px per side) are downscaled. |
cacheTtlSeconds |
90 |
How long a resolved URL is reused before the source is checked again. |
assetCacheDays |
30 |
How long downloaded textures are kept on disk. |
loadlistUrl |
"" |
Optional URL to pull the loadlist from, instead of listing sources inline. |
You need JDK 8, 17, and 21 available as Gradle toolchains; Gradle itself runs on JDK 21.
./gradlew build # core + every adapter
./gradlew :core:test # engine unit tests
./gradlew :adapters:mc-1.20.1:build # a single adapterJars are written to adapters/<version>/build/libs/. The first build of any adapter downloads and decompiles that Minecraft version, so give it time.
The logic sits in core/ — plain Java 8, with zero references to net.minecraft.*. It does the HTTP fetching, disk caching, PNG/GIF/APNG decoding, HD downscaling, slim/wide detection, and wall-clock animation timing. Each Minecraft version is a thin adapter that implements a small Platform/LiveTexture interface and mixes into the player's skin/cape getter. The 1.20.2 skin-system rewrite (the PlayerSkin record) is confined to the adapters — the core never sees a ResourceLocation or a PlayerSkin. So there is one engine and a shim per version, rather than the same mod copied eight times.