Free asset packs under the CC0 licence are one of the best things that happened to small game teams. They also produce one of the most recognisable looks in games: a knight from one pack, trees from another, a house from a third, each with its own colours and level of detail. Players call it an asset flip, and game portals' quality guidelines ask for a consistent aesthetic for exactly that reason. In our 3D browser games Faultwarden and Billowpost the characters and props come from CC0 packs, yet each game looks like itself. This article shows how: the licence check, a small script that repaints the packs' palette textures, and a build step that trims the models for the web.
#Decide what comes from packs and what stays yours
The first decision matters more than any script. In both games, packs supply only characters and props: people, enemies, trees, rocks, houses, crates. Everything that defines the look of a scene is our own: the terrain, the sky, the cloud sea, the water, the visual effects, the interface, the icons, the logo, the store covers, and all music and sound, which is synthesised in the game. The ground and the sky cover most of the screen, so when those are yours and consistent, the borrowed props sit inside your world instead of defining it.
A second rule follows from it: use one family of packs per game. Faultwarden uses three KayKit packs; Billowpost uses three Kenney kits. No game mixes the two families, and no pack is shared between the two games, so they do not look like siblings either.
#Check the licence on the day, and keep the evidence
CC0 means the author has given up their rights as far as the law allows: you may use, change and sell the work, and credit is optional. It is the simplest licence there is, but two habits are still worth it.
- Read the licence file inside the download, on the day you download. Licences change. In 2026 at least one popular free-asset creator moved from CC0 to a licence of its own with extra conditions, and we left those packs out rather than track two sets of terms. The licence that counts is the one that came with the files you actually use.
- Write it down. Each game has a third-party notices file listing every pack, its author, the source address, the download date, the licence text and what the pack is used for. For Billowpost it also records the checksum of each downloaded file, so we can prove later exactly which version we used.
We credit the authors even though CC0 does not require it, and we never use their logos or names in our own branding. A pack used "for props only" is listed with that limit, for example "trees, rocks, ruins; never its hex tiles", because the hex tiles would make the arena look like a different kind of game.
#Why repainting a texture repaints the model
Many stylised low-poly packs, including the KayKit and Kenney ones we use, do not paint each model separately. Every model in a pack shares one small palette texture, a grid of colour swatches, each a short gradient, and each face of each model points at one swatch. Change a swatch, and every surface that uses it changes colour in every model at once. That makes a whole pack recolourable with an image script, without opening a 3D editor.
A blanket hue shift would also turn faces and skin green, so the script works with masks. It converts the palette to hue, saturation and value, selects the swatches that belong to one material by ranges, and moves only those:
H, S, V = hsv(Image.open(f"{ADV}/rogue_texture.png"))
green = (H > 0.22) & (H < 0.5) & (S > 0.2) # the cloak
brown = (H > 0.02) & (H < 0.11) & (S > 0.25) & (V < 0.75) # leather
WAYS = {'teal': (0.49, 0.62, 0.95), 'ember': (0.015, 0.72, 0.95), 'moss': (0.29, 0.55, 0.85)}
for name, (th, ts, tv) in WAYS.items():
h = np.where(green, th, H)
s = np.where(green, np.clip(S * ts / 0.75, 0, 1), S)
v = np.where(green, np.clip(V * tv, 0, 1), V)
h = np.where(brown, 0.065, h) # leather turns copper in every colourway
save(rgb(h, s, v), f"oda_{name}")
Multiplying saturation and value instead of replacing them keeps the pack's own shading steps: the light and dark swatches of the cloak stay light and dark, only in a new colour. Skin and metal are not selected by any mask, so they keep their original swatches.
In Faultwarden the hero gets six colourways from one model, which the player unlocks as rewards. The enemies are skeletons in the original pack; our script turns the bone into pale slate, the cloth into a murky violet and the warm accents into ember, so they read as the stone husks of our story instead of the pack's skeletons. The boss uses the same model with darker basalt and brighter ember. The props pack is only warmed and slightly desaturated toward our art direction. The cover of this article shows a palette before and after.
#Trim and compress for the browser
A pack is made for every possible game, so it carries far more than one game needs. A build script based on glTF-Transform turns the packs into the small files the game loads:
- keep only the meshes and animation clips the game uses, and put the shared animations into one library file that every character uses;
- swap the original textures for the repainted ones, resized to 512 pixels and saved as WebP;
- weld duplicate vertices, remove duplicate data and anything unused, quantise positions and normals, and compress the geometry with meshopt.
All models in Faultwarden, with animations and textures, come to about 1.4 MB, and the whole game build is about 2.3 MB. Each hero colourway is a separate texture of about 6 KB, so six looks cost less than one photograph. The raw packs are not part of the game's repository at all: the script rebuilds everything from them on demand, and the repository keeps only our own textures and the result.
#Light it as one world
The last step happens in the renderer. Every model, borrowed or ours, sits under the same sun, the same sky light, the same fog colour and the same tone mapping, and casts shadows on our own terrain. Materials from packs come with their own roughness and emissive values; we set them ourselves, for example a matte surface and a faint teal self-light on the hero so that the character stays readable on dark or busy ground. Small things finish the job: grass tufts that belong to our own stone plates and fall with them, and dust and particles in the game's colours. When the lighting is shared, players stop seeing where a model came from.
#A checklist
- One family of packs per game, for characters and props only.
- Terrain, sky, effects, interface and covers made by you.
- Licence read in the download, recorded with date, source and checksum.
- Palette textures repainted by masks into your palette.
- Models trimmed and compressed; raw packs kept outside the repository.
- Shared lighting, fog and tone mapping; material values set by you, not by the pack.
For store images built from the real scene rather than from the packs' preview renders, see store page images for itch.io, Game Jolt and Steam. If you work in Blender rather than code, our article on batch-exporting Blender scenes to GLB and FBX covers the export side. Both games are free and listed as Coming soon in the PN Scripts games catalogue.
#Frequently asked questions
Do I have to credit CC0 asset authors?
No, CC0 does not require credit. It is still good practice to credit them in your notices and store page, without using their logos or suggesting they endorse your game.
Can I sell a game that uses CC0 models?
Yes. CC0 allows commercial use and changes. What you cannot do is claim exclusive rights over the unchanged assets, since anyone else may use them too.
How do I recolour a whole low-poly pack at once?
If the pack's models share one palette texture, repaint that texture. Select each material's swatches by hue, saturation and value ranges and move only those, so skin and metal keep their colours.
How do I avoid the asset-flip look?
Make the large surfaces yourself, such as terrain, sky and interface, use one family of packs, repaint them into your palette and light everything with the same sun, fog and tone mapping.
Comments
Comments
Be the first to leave a comment.
Leave a comment