How to use free CC0 3D models and sounds in a web game
Net Forge, the open-source multiplayer browser game engine built for AI coding agents, is published on npm under @netforge with source at github.com/netnetdev/net-forge.
The quickest way to put free, CC0-licensed 3D models and sounds in a web game is to reference them by library id: a Net Forge game says model: "style.lowpoly.bat", and the template loads the optimized glTF file and draws it in the game's art style. The ids come from @netforge/asset-library, whose built files (@netforge/asset-library-files, 536 files, about 36 MB) are installed with every template.
npm create netforge@latest my-game -- --template survivor --yes
npm install @netforge/asset-library @netforge/asset-library-filesThe first line is all you need inside a Net Forge game. The second is for using the library in a project of your own.
What is in the library
| Set | Entries | What |
|---|---|---|
lowpoly (3D) | 228 | Animated characters, monsters, animals, dinosaurs, robots, tanks, weapons and props from Quaternius, and Kenney's character, car, blaster, nature, space, food and city kits |
ps1 (3D) | 238 | The same kinds of models in a late-1990s console look |
voxel (3D) | 227 | Block-built versions |
pixel (2D) | 58 | Sprites from Kenney's Tiny Dungeon, Pixel Platformer and Pixel Vehicle packs |
audio | 18 | 17 sound effects, one per game-feel cue, and one music loop |
The toon and handdrawn art styles are drawn by the engine from the 3D models, so a game can switch between all six styles: lowpoly, toon, ps1, pixel, voxel and handdrawn.
Every model and sound is third-party art under CC0 1.0, a public domain dedication, so it can be used in commercial games without attribution. The package's NOTICE lists every pack, where its licence was verified, and credits the authors anyway: Quaternius, Kenney and others. Each file's bytes are pinned by sha256.
1. Use models in a Net Forge game
In src/game.ts, models are always library ids, never URLs or paths:
import { prefab } from "@netforge/engine";
prefab("wisp", { model: "style.lowpoly.bat", health: 8, speed: 5, radius: 0.25, damage: 4, ai: "chase", drops: ["ember_small"] });
prefab("brute", { model: "style.lowpoly.orc_brute", health: 160, speed: 2.2, radius: 0.8, mass: 6, damage: 14, ai: "tank", drops: ["ember_small"] });The game's style decides how they draw. A style.lowpoly.<name> id draws as that style's own model of the same name when the style has one, so the same file works in every style. An id that is not in the library fails at once with a line that says so.
2. Find models by description
import { assetById, inEveryStyle, restyleId, search, soundBank, stockedStyles } from "@netforge/asset-library";
console.log("styles with models:", stockedStyles().join(", "));
// Find models by description, in one style.
for (const hit of search("lowpoly", "monster truck", 3)) console.log(hit.asset.id, "-", hit.asset.line);
// The same model in another style.
console.log(restyleId("style.lowpoly.bat", "voxel"));
// The same ids in every stocked style, for example to preload before a style switch.
console.log(inEveryStyle(["style.lowpoly.bat", "style.lowpoly.truck"]));
// Where an asset came from.
const bat = assetById("style.lowpoly.bat");
console.log(bat?.source);
// Sound effects for the engine's SoundPlayer: cue name to URL under your library base.
const bank = soundBank("/library");
console.log(Object.keys(bank.cues).join(", "));The package ships TypeScript source, so run this with a TypeScript runner such as npx tsx find-assets.ts or inside a Vite project. It prints lowpoly, pixel, ps1, voxel, then style.lowpoly.monster_truck - pickup truck on giant wheels and two more trucks, then style.voxel.bat, the source of the bat (its Poly Pizza model page and file hash), and the cue names hit, impact, kill, bigKill, hurt, levelUp, gem, coin, dash, step, land, boss, ui, pick, downed, revive, shoot.
3. Use the files in your own Vite project
@netforge/asset-library/vite exports assetLibrary(), a Vite plugin that serves the library at ./library in development and copies only the models a game uses into its build. Point its dir at node_modules/@netforge/asset-library-files/library. @netforge/asset-library/three exports LibraryClient, which loads models through the engine's AssetLoader (glTF with meshopt and KTX2), prepares them (facing, scale, tint) and animates characters through shared rigs with the canonical clips idle, walk, run, jump, attack, shoot, hit and die.
How it works
Each style is one JSON manifest. Every entry has an id, a kind, a body plan (biped, quadruped, flyer, blob, wheeled or static), a rig, its source (an archive path or a pinned file URL with its licence page), a height, one plain description and search tags. The fetch script downloads each pack from its official source, and the Net Forge asset pipeline optimizes it into the built files. Characters from the same author share one rig and clip set, which is why one animation system drives all of them.
Alternatives
- Kenney publishes large CC0 asset packs for 2D and 3D games. Download them directly when you want the original packs and formats.
- Quaternius releases CC0 low-poly model packs, many of them animated.
- Poly Pizza is a searchable library of low-poly models with the licence shown on each model page. Check each one, because not every model there is CC0.
- OpenGameArt hosts free art and audio under several licences, CC0 among them.
Pick the Net Forge library when you want those CC0 assets already optimized, addressed by id, rigged to shared clips and drawable in six art styles.
FAQ
What does CC0 mean for my game?
CC0 1.0 is a public domain dedication: you may copy, modify and use the work, including commercially, without asking or crediting. Crediting is still a kind gesture, and the library's NOTICE does it for you.
Can I use these assets outside Net Forge?
Yes. The models and sounds are CC0, and the library package's code is MIT licensed.
Can I add my own models?
In a Net Forge game, src/game.ts references library ids only, so a model has to be in the library. In your own project you can load any glTF file with three.js next to the library's models.
Why ids instead of file paths?
An id is checked against the library when the game is defined, so a typo fails at once with a clear line. It also lets the same game draw in another art style, where the id maps to that style's own model.
How big are the files?
The full built library is 536 files and about 36 MB unpacked. The Vite plugin copies only the models a game uses into its build.