Skip to content

Latest commit

 

History

History
110 lines (82 loc) · 15.1 KB

CONTRIBUTING.md

File metadata and controls

110 lines (82 loc) · 15.1 KB

Contributing

This repo catalogs links and metadata for free (preferably commercially usable) game assets and related tools. It does not host binary asset dumps.

Please follow the Code of Conduct.

What belongs here

  • Asset libraries, packs, and aggregators with a clear free tier
  • Tools useful for creating or processing game assets
  • Free engine add-ons / plugins that materially help asset or production pipelines (e.g. Godot Asset Library tools)
  • Engines only when they ship substantial free asset libraries

Accepted with caveats

  • A source whose licence is unclear: add it as status: needs-review with the open question in Notes, or open an issue instead.
  • A source that is free only for non-commercial or personal use: only if it is clearly marked commercial: false and the Evidence section quotes the restriction (the validator checks this). The site shows a "Not for commercial use" banner on such entries, and the Commercial OK filter hides them.

What does not

  • Paid-only marketplaces with no free content worth listing
  • Broken or abandoned sources
  • Redistributed ZIP/GLB/WAV files of third-party work
  • GTA V / RDR2 extracts, FiveM MLO leaks, Tebex reuploads, and anonymous fivem-props dumps (see docs/fivem.md and docs/high-risk.md)

Adding an entry

The website rebuilds from frontmatter on deploy. Node 22 or newer is all you need (CI and .nvmrc use 24); there are no dependencies to install.

  1. Run node site/new-entry.mjs <category> <id> (or npm run new-entry -- <category> <id>). It copies catalog/TEMPLATE.md to catalog/<category>/<id>.md with the id, category and today's date filled in, and refuses an id already used anywhere in the catalog. Use a short kebab-case id; a mixed kit already listed in another category is a duplicate, not a second entry.
  2. Verify the license on the live source page the day you submit, and fill every frontmatter field from it (rules below). Prefer primary URLs over mirror/aggregator pages.
  3. Write the body: a one-paragraph summary, ## Notes, ## Evidence with a dated line quoting the source, such as - Live page (2026-09-25): "Free for commercial use", and optionally ## Related linking sibling entries. Every Evidence section needs at least one date, and verified may not be newer than the newest one. The template (and so the scaffold) starts at status: needs-review; set active once the licence, the commercial stance and the credit requirement are all settled.
  4. Add a row to the matching category README.md. This is required: the validator fails an entry that is not listed there, and the row's licence cell must match your frontmatter.
  5. Run node site/sync-counts.mjs (npm run counts). It updates every place the repo restates the entry count: both category count tables, the README badge and "Browse N sources" line, and expectedEntryCount in site/config.json.
  6. Run npm test && npm run validate before you push; that is quick. CI then runs npm run check (the tests, node site/validate.mjs and node site/build.mjs), and all of it must pass. Run npm run check yourself if you changed the site or want to preview your entry's page. The build renders your entry's page and fails if the body uses markdown the site does not support (tables, code fences, blockquotes, images, raw HTML, ### headings, numbered lists) or links to a file that does not exist.
  7. Save files with LF line endings. .editorconfig and .gitattributes take care of it in most editors; the validator rejects a file that still contains a CR.
  8. Optional: add the id to site/config.json → featured to pin it under Safe starting points.

To add a starter stack (one pick per need for a kind of game), follow stacks/README.md.

Frontmatter rules

  • license: the source's licence, written as one of the values in site/license-vocabulary.json (e.g. CC0, CC-BY-3.0, SIL OFL, GPL-3.0-or-later, custom, varies). If the source uses a licence the vocabulary lacks, add it there first, with its SPDX mapping and attribution class. For GPL, record -only or -or-later only when the project itself says which; otherwise use the bare GPL-2.0 or GPL-3.0.
  • license_spdx: the SPDX identifier the vocabulary maps your license to. The validator rejects a missing one when a mapping exists, and an invented one when it does not.
  • commercial: true / false / unknown / varies. Use varies for aggregators where some files are commercial-ok and others are not. The site still shows these under Commercial OK, labeled per-file review, so they are not silently excluded and not silently treated as a blanket grant.
  • attribution_required: true / false / unknown. If the licence normally requires credit (CC-BY) but the publisher waives it, set false and add a - Attribution waived: line in Notes saying so.
  • attribution_string: the copy-paste credit line. Required when attribution_required is true; optional otherwise.
  • publisher: optional. Name the rights-holding publisher, never the host. Set it whenever that publisher has more than one catalog entry, so each entry page names the same publisher and the validator can check that the group agrees; setting it on a publisher that currently has only one entry is also fine and saves a backfill later. Do not set it to a generic host or distributor (GitHub, Hugging Face, itch.io, OpenGameArt, the Internet Archive, Google Fonts) or to a distributor that does not hold the rights. Distinguish sibling organisations that are genuinely different rights holders: blender.md (the application, Blender Foundation) carries no publisher, while the asset bundles under studio.blender.org carry Blender Studio. Kenney, Quaternius, KayKit, LuizMelo, 0x72, Blender Studio, Material Maker, Alif Type, GGBotNet and 3dmodelscc0 are the largest groups in use today; treat that as illustrative, not as the permitted set.
  • subcategories: lower-case kebab-case (base-meshes, field-recordings). Reuse a value already in the catalog before inventing one, and do not add a variant of an existing value that differs only in plural or spelling. Where both forms were in use, the more common one was kept (characters, environment, interior, tileset, vectors, pixel, impulse-responses, base-meshes). Retired spellings are listed in site/value-aliases.json, which the validator enforces (V19); add a line there when you merge two values.
  • formats: what you actually get, in one of four kinds. File formats, as commonly written: usually upper case (PNG, FBX, JSON, VOX), tool-specific ones as the tool writes them (gdshader, tmx, ktx2). Engine or language targets, as the product writes them (glTF, Godot, Unity, Python, React). Delivery types for software with no file format of its own, lower-case kebab-case (godot-addon, blender-extension, npm, cli, library, desktop-app, mobile-app, middleware, model). And various for an aggregator whose files come in too many formats to list. Platforms (windows, macos, ios) and descriptions (heightfield, examples) are tags, not formats. The allowed values are the closed list in site/format-vocabulary.json, which the validator enforces (V20): reuse a listed spelling, and add a genuinely new format there in the same change that first uses it. Its groups drive the site's Format filter, so a new format that belongs to a group (another glTF or font container) goes into that group too. A format outside every group is still searchable and shown on the card, but the Format filter cannot select it.
  • tags: lower-case kebab-case words describing the content (low-poly, modular, platformer). Do not restate another field: the licence (cc0, mit, ofl, open-source, royalty-free), the credit requirement (no-attribution) or the entry's own publisher (kenney) are rejected (V19 via site/value-aliases.json, V21), because search and the filters read those fields directly and a copied tag drifts. A varies entry lists its licence mix in the body, not in tags.
  • Frontmatter is one key: value per line; lists are [a, b] or indented - item lines. A key given twice is an error. Entry files may not contain emoji.
  • grid_dimensions / camera_perspective / hardware_tags: optional metadata for 2D and UI entries. 3d and characters entries leave camera_perspective out: it describes a 2D camera, and those entries have none.
  • maintenance: optional, archived | inactive (V22). Set archived when the source repository is archived, and inactive when it has had no push for over three years, with a dated - Maintenance: line in Notes saying what you read. Leave it out otherwise. The weekly link check reports a GitHub source whose state no longer matches.
  • engine_lock: optional, unreal (V23). Set it only when the licence restricts use to products built with that engine, as Epic's "UE-Only Content" listings do, and quote that line in Evidence. The site shows a UE only badge. Leave it out for content that is merely made for an engine.
  • ue_versions: optional, the Unreal Engine versions the source itself states, as 5.4, 5.4-5.8 or 5.4+ (V23). Say in Notes where the range came from (README, .uplugin, release names, listing). Never infer it.
  • Unreal plugins use subcategories: [unreal, ...] and formats: [unreal-plugin]; Unreal projects and content packs use formats: [Unreal]. The validator rejects a GPL or LGPL licence on either, because the Unreal Engine EULA forbids combining the engine with that code (see docs/unreal.md).
  • url: an https:// address (http:// only where the source has no https). Other schemes are rejected.
  • added: ISO date (YYYY-MM-DD) the entry joined the catalog. npm run new-entry fills it in; it never changes afterwards (V26: a real date, not in the future). The "new sources" feed and the home page's "New in the last 30 days" line key on it, so a re-verification sweep does not look like a wave of new entries.
  • verified: ISO date (YYYY-MM-DD) of your last license check. It must be a real date, no later than tomorrow in UTC, and no newer than the newest date in ## Evidence (V8): a new verified date needs a new dated Evidence line from the same check. Dates inside URLs do not count as Evidence dates.
  • status: active | needs-review | deprecated. A deprecated entry needs a - Deprecated: line in its body giving the reason (V9). active means the licence, the commercial stance and the credit requirement are all settled: an unknown in license, commercial or attribution_required keeps an entry at needs-review. The validator enforces this (V14), and rejects formats, subcategories or tags values that differ only by case, punctuation or a trailing "s" from one already in use (V13).

License verification checklist

  • License text or badge visible on the source
  • Commercial use explicitly allowed (or marked false) — free download ≠ commercial
  • Interactive/game use confirmed, not just "commercial use" in the abstract (see docs/game-vs-video-licensing.md)
  • Attribution / share-alike / NC / ND flags recorded
  • Marketplace EULA checked if Unity/Fab/Unreal/itch
  • Supplier looks reputable (not an anonymous laundering risk — see docs/provenance.md)
  • Not on the docs/high-risk.md blocklist (MB-Lab, default Shadertoy, ND music, Unity Companion, GTA/FiveM rips, etc.)
  • Entry does not claim rights we don’t have
  • Tool entries distinguish software license from exported asset ownership

Verification ages. On the first of each month a workflow opens a "Re-verify batch" issue listing the live entries whose licence was read longest ago (over 150 days, about a tenth of the catalog). Each item is a self-contained re-read: open the source, confirm the terms, bump verified and add a dated Evidence quote, or set needs-review and say what changed. Those issues carry good first issue; pick one if you want a first contribution with no code.

Submitting your own source

Publishers are welcome to list their own work. Say so in the pull request, write the entry as a third party would (facts the source states, no comparisons with other entries, no ranking language), and start it at needs-review so a maintainer re-reads the licence before it goes active. A free tier of a paid product is listed as the free tier only, with the paid tier named in Notes and not linked as the entry's url. A one-time notice or upsell inside a tool is recorded in Notes as a fact.

Preview images

The site shows each entry's preview image where it can. The picture is the publisher's own og:image from the entry's url, fetched by npm run thumbs, resized to 640 pixels wide and committed under site/public/thumbs/ with a record in site/thumbs.json. The gate in site/lib/thumbs.mjs is narrower than "the licence is open":

  • the entry must be active, and its licence on the allowlist (CC0, CC-BY, MIT, OFL, GPL and the other open licences that allow a resized copy); custom, varies and unknown never get one;
  • tools and fonts entries only get a thumbnail from a maintainer-checked preview: URL, because the page image there is a logo, splash screen or social card that the program's or font's licence does not cover;
  • a CC-BY entry needs attribution_string or publisher, because the caption has to name the creator;
  • GitHub repositories are skipped, since their social card is not a preview.

What the gate does not verify: an itch.io store cover is taken to be under the pack's licence, which the pack's licence text does not always say; a publisher who disagrees can ask for preview: none (below). The validator fails when a committed image no longer passes the gate, and the script removes it on its next run.

A publisher who would rather not have their preview shown can open an issue; the maintainer sets preview: none on the entry and the image is removed. A maintainer who has checked that a specific image is covered by the entry's licence can set preview: https://... to use that image instead of the page's og:image.

Automated and AI-assisted pull requests

Changes drafted with an agent or a script are judged on the diff like any other. Keep them small, keep tests in site/checks.test.mjs or site/lib/lib.test.mjs (a test file that npm test does not run is dropped), and name the issue the change fixes in the body (Fixes #N). A pull request that lists sources or licences the author did not read is closed: the catalog's one rule is that every licence fact was read at the source by the person who recorded it.

Licence of contributions

By opening a pull request you dedicate your contribution to the public domain under CC0 1.0, like the rest of the repository's metadata and documentation. Quotes from licence pages stay the publisher's words; they are used as short factual quotations, and the assets they describe keep their own licences.