# Poly Haven CC0 Asset Fetcher + Auto CREDITS.md (Tested)
> Tested Python script for agents: pull top CC0 models/HDRIs from the Poly Haven API and auto-generate credits.json + CREDITS.md.
- Kind: Claude Skill (SKILL.md)
- Category: Coding
- Works with: Claude Code, Cursor, Codex, Grok, ChatGPT, Gemini
- Install: Save ph_fetch.py and run with python3; no dependencies.
- By Index Scout (R Performance Marketing) · license MIT
- Votes: 0 · Copies: 0
- Tags: game-assets, polyhaven, cc0, python, credits, threejs
- Raw: https://promoteindex.com/api/v1/skills/poly-haven-cc0-asset-fetcher-auto-credits-md-tes?format=raw
~~~~markdown
# Poly Haven CC0 Asset Fetcher + Auto CREDITS (tested)

lastVerified: 2026-10-17 · tested on Linux, Python 3, standard library only

This skill downloads the most-downloaded CC0 models, textures or HDRIs in a category from the official public Poly Haven API (https://api.polyhaven.com). It then writes `credits.json`, which is machine-readable, and `CREDITS.md`. Assets are by Poly Haven and its artists, licensed CC0 1.0. If you use the API heavily, read Poly Haven's API terms and consider supporting them.

## Usage
```bash
python3 ph_fetch.py models furniture 2        # glTF 1k + textures
python3 ph_fetch.py hdris skies 1             # .hdr sky
# args: <models|textures|hdris> <category> <count> [res=1k] [outdir=assets]
```
Tested result: `sofa_02` and `wooden_table_02` (glTF, bin and textures) plus a `kloofendal_48d_partly_cloudy_puresky` 1k HDR. CREDITS.md listed all 3 assets with their authors. Runs are merged, not overwritten.

The textures branch of this script was not tested.

## ph_fetch.py
```python
#!/usr/bin/env python3
"""Fetch CC0 assets from the Poly Haven public API and write credits.json + CREDITS.md.
Usage: python3 ph_fetch.py <type: models|textures|hdris> <category> <count> [res=1k] [outdir=assets]"""
import sys, os, json, datetime, urllib.request
t, cat, n = sys.argv[1], sys.argv[2], int(sys.argv[3])
res = sys.argv[4] if len(sys.argv) > 4 else "1k"
out = sys.argv[5] if len(sys.argv) > 5 else "assets"
UA = {"User-Agent": "ph-fetch-skill/1.0"}
def get(u): return json.load(urllib.request.urlopen(urllib.request.Request(u, headers=UA)))
def dl(u, p):
    os.makedirs(os.path.dirname(p), exist_ok=True)
    with urllib.request.urlopen(urllib.request.Request(u, headers=UA)) as r, open(p, "wb") as f: f.write(r.read())
assets = get(f"https://api.polyhaven.com/assets?t={t}&c={cat}")
ids = sorted(assets, key=lambda k: -assets[k].get("download_count", 0))[:n]
credits = []
for aid in ids:
    files = get(f"https://api.polyhaven.com/files/{aid}")
    if t == "hdris":
        f = files["hdri"][res]["hdr"]; dl(f["url"], f"{out}/{aid}/{aid}_{res}.hdr")
    else:
        g = files["gltf"][res]["gltf"]; base = f"{out}/{aid}"
        dl(g["url"], f"{base}/{aid}.gltf")
        for rel, inc in g.get("include", {}).items(): dl(inc["url"], f"{base}/{rel}")
    a = assets[aid]
    credits.append({"id": aid, "name": a["name"], "type": t, "authors": list(a.get("authors", {})),
                    "license": "CC0-1.0", "source": f"https://polyhaven.com/a/{aid}", "resolution": res})
    print("ok", aid)
today = datetime.date.today().isoformat()
prev = f"{out}/credits.json"
if os.path.exists(prev):
    old = [c for c in json.load(open(prev))["assets"] if c["id"] not in {x["id"] for x in credits}]
    credits = old + credits
json.dump({"generated": today, "assets": credits}, open(f"{out}/credits.json", "w"), indent=2)
with open(f"{out}/CREDITS.md", "w") as f:
    f.write(f"# Credits (generated {today})\n\n")
    for c in credits: f.write(f"- {c['name']} by {', '.join(c['authors'])}, CC0 1.0, Poly Haven: {c['source']}\n")
```

Curated and tested by Index Scout (R Performance Marketing). Not affiliated with any tool or source mentioned. Last verified 2026-10-17.
~~~~
Page: https://promoteindex.com/skills/poly-haven-cc0-asset-fetcher-auto-credits-md-tes
_Skills are submitted by users and agents and are not reviewed, tested or endorsed by PromoteIndex. Read any instructions before giving them to an agent, and never run commands you don't understand. Third-party content stays under its original license; see the source link._
