◐
material · drop-in viewer
asset⌬ materialmaterialprimary: mat.yaml·part ofpackage metalsMaterials.package·originates fromworld c5a5982c-c…
What it does
No description provided yet.
Interface
What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.
This asset doesn't declare a schema or structured payload.
Sub-parts
Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.
Showing up to 3 levels deep. Open a part to see what it holds further down.
9+items
▲ 0↑ born
# metalsMaterials: Forge and Patina
28 seamless, real-scale, physically based metals for the materialLibraryKit material library, from mirror chrome to flaking rust, plus a toon set. Version 1.0.4.
**Two guides come with the package.** After installing, open them in the engine shell by their folder path (with metalsMaterials installed at the top of your world, as a normal install puts it):
- **"Metal materials for your game: how to make something look like rusty, brushed, polished or painted metal"**: `zero guides read --path metalsMaterials.package/guides/metalMaterialsForYourGame`. What the collection is and how it fits with the material library, putting a metal on something for every player, finding metals by type, style, tags and search words, what tile size means, swapping metals, when to use the world-aligned rust on blocky shapes, toon versus realistic, and how the metals go together with the other material collections and the library's own guides.
- **"Build a rusty metal workshop with metal materials"**: `zero guides read --path metalsMaterials.package/guides/buildARustyMetalWorkshop`. A worked example from an empty world to a corrugated shed with a tread plate floor, an anvil, patinated copper pipes with brass fittings, a shiny toolbox, a worn painted pillar drill and a little robot, then one change that turns it into an abandoned rusted ruin or a cartoon.
Installed somewhere else (for example as another package's dependency, under `/source/deps/<world id>/`), `zero guides list` prints each guide's folder path.
New in 1.0.4:
- **The two guides above.** Every step of the workshop guide was run word for word in a new world.
- **One library next to the other collections.** metalsMaterials now depends on materialLibraryKit 1.4.2. With 1.0.3, a world that also held a collection published against another release of the library could list two calibration shelves and 20 duplicate-id problems; the library from 1.4.0 on leaves the older copy out, so the metals sit next to the woods, stone, sci-fi and other collections in one library. A fresh install of 1.0.4 brings the package and the library, without the pinned copies of older library modules 1.0.3 laid under `/source/deps/<world id>/versions/`.
- **The first README example spawns a shared cube** (`synced = true`), so every player really has the cube whose metal they are told they see.
- No metal, material, texture or call changed.
New in 1.0.3:
- **The tests pass the first time in a new world.** In a world that had never shown the gallery, 1.0.2's gallery check looked for the metals' bays before the first build had placed them, so its first run failed one test and only a second run passed. The check now waits for each gallery page's bays to land before counting them, and clears the gallery again afterwards when the world had none.
- **The tests pass wherever the package is installed,** including under `/source/deps/` as another package's dependency.
**Coming from 1.0.1 or earlier?** Update to 1.0.4, then `zeromind.removeUnusedDeps({ dryRun = true })` lists the engine copies 1.0.1 left under `/source/deps/` and `zeromind.removeUnusedDeps()` removes them.
Install it and the metals turn up in the library's list, picker and swatch gallery on every player's machine, with no setup code. The materialLibraryKit core is a declared dependency, so it installs along with this package.
## Install and use
Install the package from ZeroMind (search "metalsMaterials" or "Forge and Patina", or install the published package `5e629c69-714e-4e53-99bb-f7b64222b316`). It lands at `/source/metalsMaterials.package`; the core comes with it as a dependency under `/source/deps/`. Scripts reach the core by its package name with `~`, wherever it was installed (`@root::` would only look at the top of your world). Then, from any script:
```luau
local Materials = require("~materialLibraryKit.Materials")
local cube = entity.spawn("cube", { synced = true, components = { Model = { model = "cube" } } })
cube.localPosition = { 0, 1, 3 }
Materials.apply(cube, "brushedSteel") -- every player sees it
-- swapping the metal changes only the name
Materials.apply(cube, "copperPatina")
for _, m in Materials.list({ collection = "metals", kind = "iron" }) do
print(m.id, m.style, m.tileSize, m.textureKB)
end
```
To walk round every metal, drop the gallery into a scene. `MetalsShowcase` opens it on the metals page and hangs each metal's reference picture beside it.
```luau
local g = entity.spawn("Gallery")
g.component.add("SwatchGallery", {})
g.component.add("MetalsShowcase", {})
```
The world this package comes from, "Forge and Patina: The Metals Material Collection", opens straight into that gallery, with the lighting looks (daylight, overcast, golden hour, moonlight, warm interior, studio) switchable live from the toolbar.
## The metals
Every metal is tagged `category = metal`, with its `kind`, its `style`, `tileSize` (metres covered by one texture repeat), roughness and metallic ranges, `textureKB` (GPU texture memory, mipmaps included), `animated = false`, and plain search words. Filter on any of them, for example `Materials.list({ collection = "metals", search = "rusted" })` or `Materials.list({ style = "toon", kind = "copper" })`.
| Name | Metal | Kind | Style | Tile (m) | Roughness | Metallic | Texture memory | Search words |
|---|---|---|---|---|---|---|---|---|
| `steelRaw` | Raw mill steel | steel | realistic | 1 | 0.49-0.7 | 0-1 | 4.0 MB | raw, mill scale, hot rolled, industrial, bare |
| `brushedSteel` | Brushed steel | steel | realistic | 0.5 | 0.3-0.41 | 1 | 1.0 MB | brushed, satin, stainless, grain, appliance |
| `polishedChrome` | Polished chrome | steel | realistic | 0.5 | 0.06-0.08 | 1 | 341 KB | polished, mirror, chrome, shiny, plated |
| `galvanisedSteel` | Galvanised sheet | steel | realistic | 0.5 | 0.2-0.54 | 1 | 1.0 MB | galvanised, zinc, spangle, sheet, crystalline, patterned |
| `corrugatedSheet` | Corrugated sheet | steel | realistic | 0.762 | 0.36-0.53 | 1 | 1.3 MB | corrugated, ridged, roofing, sheet, galvanised, patterned |
| `diamondPlate` | Diamond tread plate | steel | realistic | 0.5 | 0.66-0.75 | 1 | 5.3 MB | tread, diamond plate, checker plate, floor, industrial, patterned |
| `damascusSteel` | Damascus steel | steel | realistic | 0.6 | 0.44-0.58 | 1 | 4.0 MB | damascus, folded, pattern welded, blade, etched, patterned |
| `castIron` | Cast iron | iron | realistic | 0.5 | 0.74-0.85 | 1 | 1.3 MB | cast, sand cast, rough, dark, foundry |
| `rustedIronLight` | Rusted iron (light) | iron | realistic | 1 | 0.45-0.89 | 0-1 | 5.3 MB | rusted, rust, weathered, surface rust, corroded |
| `rustedIronHeavy` | Rusted iron (heavy) | iron | realistic | 1 | 0.55-0.93 | 0-1 | 5.3 MB | rusted, rust, weathered, heavy rust, corroded, scale |
| `rustedIronFlaking` | Rusted iron (flaking) | iron | realistic | 1 | 0.31-0.93 | 0-1 | 5.3 MB | rusted, rust, flaking, peeling, bare metal, corroded |
| `rustedIronBlocky` | Rusted iron (blocky shapes) | iron | realistic | 1 | 0.55-0.93 | 0-1 | 4.0 MB | rusted, rust, triplanar, blocky, no uv, world space, level blockout |
| `aluminiumBare` | Bare aluminium | aluminium | realistic | 0.5 | 0.37-0.48 | 1 | 1.0 MB | aluminium, aluminum, bare, mill finish, light |
| `anodisedRed` | Anodised aluminium (red) | aluminium | realistic | 0.5 | 0.39-0.44 | 1 | 683 KB | anodised, anodized, coloured, red, satin |
| `anodisedBlue` | Anodised aluminium (blue) | aluminium | realistic | 0.5 | 0.39-0.44 | 1 | 683 KB | anodised, anodized, coloured, blue, satin |
| `anodisedBlack` | Anodised aluminium (black) | aluminium | realistic | 0.5 | 0.39-0.44 | 1 | 683 KB | anodised, anodized, coloured, black, satin, camera body |
| `copperNew` | New copper | copper | realistic | 0.5 | 0.14-0.2 | 1 | 341 KB | copper, new, polished, shiny, warm |
| `copperPatina` | Copper with patina | copper | realistic | 1 | 0.38-0.88 | 0-1 | 5.3 MB | patina, verdigris, weathered, green, aged, roof |
| `hammeredCopper` | Hammered copper | copper | realistic | 0.3 | 0.24-0.36 | 1 | 1.0 MB | hammered, dimpled, handmade, planished, copper, patterned |
| `brass` | Brass | brass | realistic | 0.5 | 0.2-0.28 | 1 | 341 KB | brass, polished, yellow, fittings |
| `bronze` | Bronze | bronze | realistic | 0.5 | 0.37-0.56 | 1 | 1.0 MB | bronze, cast, statue, warm, aged |
| `polishedGold` | Polished gold | gold | realistic | 0.5 | 0.11-0.15 | 1 | 341 KB | gold, polished, shiny, precious, jewellery |
| `polishedSilver` | Polished silver | silver | realistic | 0.5 | 0.09-0.12 | 1 | 341 KB | silver, polished, shiny, precious, cutlery |
| `paintedMetalChipped` | Painted metal (chipped) | steel | realistic | 1 | 0.45-0.84 | 0-1 | 5.3 MB | painted, chipped, worn, edges, machinery, green |
| `toonSteel` | Toon steel | steel | toon | 1 | 0.4 | 0 | 85 KB | toon, cartoon, cel, stylised, steel |
| `toonGold` | Toon gold | gold | toon | 1 | 0.4 | 0 | 85 KB | toon, cartoon, cel, stylised, gold, treasure |
| `toonCopper` | Toon copper | copper | toon | 1 | 0.4 | 0 | 85 KB | toon, cartoon, cel, stylised, copper |
| `handPaintedIron` | Hand-painted iron | iron | stylised | 2 | 0.85 | 0 | 683 KB | hand painted, painterly, stylised, iron, rivets, fantasy |
`rustedIronBlocky` is the heavy rust projected triplanar in world space at 1 m, so it looks right on big blocky shapes (level blockouts, crates, walls) whatever their texture layout.
### Texture memory
- **Resident on the GPU, all 28 metals: 40.75 MB.** The anodised colours share one set of maps, as do the three toon metals, so the total is less than the per-metal sum.
- **Per-metal sum: 56.2 MB.** That is the sum of the "Texture memory" column, counting shared maps once for each metal that uses them.
- **Reference pictures: 9.3 MB** (28 at 512 px, BC7). They are only loaded where the gallery shows them.
- **Everything together: 50.1 MB**, about half the 100 MB target.
- The largest metal is 5.3 MB. Every metal binds at most 5 sampled textures (the web limit is 9) and no storage buffers, and passes `Checks.budget`.
- Textures are UASTC and transcode to BC7 on desktop and ASTC on mobile.
### Frame rate
- **Web build: 30 fps p50** (frame time p50 33.3 ms over 200 frames), measured 27 October 2026 in the swatch gallery with all 28 bays and their reference pictures, zero build 5f4a72e58b, Chrome on a Linux desktop, 840x632 viewport. The gallery world's own resolution helper had stepped the scene down to its 40% floor (336x252) and its badge read 23 to 28 fps. Most of each web frame goes to the engine's multiplayer updates, not to drawing the metals (see Known limits).
- **Native desktop editor:** about 80 fps in the same gallery.
- These are the 1.0.2 numbers. 1.0.4 changes no metal, texture or gallery code, and the web check was not repeated for it because it cannot be started from inside the engine (#20946).
## How they were made
- **Baked procedurally in Luau** (`MetalRecipes`, `MetalBaker`). Every map is periodic, so it tiles seamlessly by construction and is drawn at real scale: 1 unit = 1 m.
- Diamond plate lugs are 26 × 7 mm and 1.2 mm high, on a 31.25 mm pitch.
- Corrugation is a 76.2 mm (3 in) pitch with 18 mm deep ridges.
- Painted-panel rivets are 16 mm domes at 50 mm pitch, on 1 m plates.
- Hand-painted iron plates are staggered rows 0.6 to 0.7 m tall on a 2 m repeat, with 16 mm rivets about every 150 mm.
- Hammer dents are about 2 cm across. Damascus layers are about 3 cm per light and dark pair.
- **Physically based.**
- Albedo carries no painted-in light or shadow. Cavity darkening lives in the ambient-occlusion channel.
- Bare metal is metallic 1. Rust, patina, paint, primer and mill scale are dielectric (metallic 0), so on the rusted, painted and patinated metals only the exposed metal shines.
- Roughness follows the real surface: chrome 0.06-0.08, polished gold and silver 0.09-0.15, cast iron 0.74-0.85.
- Normal maps use the green-up convention, checked with a bump-direction test.
- **Kept calm at a distance.** The corrugated sheet's ridge normals are baked at 50% strength so the fine ridges don't sparkle far away. Every metal passes the core's 30 m shimmer check; the flaking rust is the closest to the limit (5.75 of 6).
- **Toon metals** use a small cel shader shipped in the package (`toonMetal`): a hard light/shadow step, a lifted shadow, a crisp highlight and a rim line, with no metalness, so they read cleanly in cartoon worlds under every lighting look. `handPaintedIron` is a stylised, non-metallic material with inked plate seams, flat-painted rivets and lighter worn edges.
- **Reference pictures.** Every metal has a reference picture (`references/<id>`), generated before its material and compared with it side by side in the gallery. The gallery hangs it on the metal's bay.
## Checked
Every metal passes all of the core's `Checks.run`: the render passes, the seam check over a 4×4 tiling, the near (1 m) and far (30 m) views with the shimmer score, texture memory and the web budget. The package's test suite reruns all of them and also covers the tags, the costs, apply/swap/clear, the picker, the gallery, the reference pictures and this README. It passes on its first run in a brand-new world and on every run after, and wherever the package is installed, including under `/source/deps/` as another package's dependency. To run it:
```luau
asset.resolve("metalsMaterials", "testSuite"):run()
```
## Multiplayer
`Materials.apply` goes through the core's shared `materials` channel, so a metal one player puts on something shows on every player's machine, and players who join later get it too. That needs every player to have the object: something that is part of the scene, or spawned with `synced = true`. An object spawned without it exists only on the machine that spawned it. Gallery swatches are local to each machine and cost the network nothing.
To try it with a second player, join from a second account: two engines signed in to the same account are counted as one player and collide (#14448).
## Known limits
- **Polished metals mirror the sky.** Chrome, silver, gold, copper and brass take on the colour of whatever the scene's sky reflects, so they look bluish in daylight and dark in a scene with no sky. That is correct for mirror metals, but it can surprise: under the daylight sky brass reads pale cream rather than deep gold, and polished silver, brushed steel and bare aluminium read as an even sheen from a few metres away, because their grain and polish are millimetre-scale.
- **`toonSteel` reads dim at night.** It is dark grey-blue by design, and dim in the moonlight and warm interior looks.
- **The core's toolbar on phones.** On a phone-width screen the core's gallery toolbar shrinks to small buttons. That is materialLibraryKit's interface; the metals and their labels stay readable.
- **The core's texture measurements read 0 for a dependency install.** When metalsMaterials comes in as another package's dependency (under `/source/deps/`), materialLibraryKit's `Materials.measureTextures` and `Checks.textureMemory` report 0 bytes for these metals: they look textures up by the names in the core's own index, which a dependency's textures are listed under with their `deps.` prefix. The metals still draw fully textured, and the `textureKB` tag on every metal gives the real cost. Installed at the top of a world, the core measures them normally.
- **The gallery runs at 30 fps on the web (#20750).** On the web build the engine spends 14 to 46 ms of every frame sending multiplayer updates, even when nothing changes, so the swatch gallery holds about 30 fps there (see Frame rate) while the native editor draws it at about 80. The metals themselves are within the web texture budget.
- **The anodised coat follows the texture under it (#21208).** The engine's clear coat uses the surface's own normal map, so on `anodisedRed`, `anodisedBlue` and `anodisedBlack` the coat's highlight shows the fine bead-blasted texture instead of lying smooth over it. Up close the coat reads slightly grainier than real anodising; at arm's length it looks the same.
- **The guides are not found by ZeroMind search yet (zero #22181, ZeroMind#3099).** Guides inside a published package do not show up in ZeroMind search, so the two guides above are found once the package is installed, with `zero guides list` or the folder paths given at the top of this README.
- **A package guide opens by its folder path (#22286).** Open the guides with `zero guides read --path metalsMaterials.package/guides/<name>` as shown above; where the package sits under `/source/deps/<world id>/`, put that in front.
- **Toon metals draw magenta in the debug views (#21225).** `toonSteel`, `toonGold` and `toonCopper` light themselves in the `toonMetal` shader, and the engine's albedo, roughness and other debug views have no way to read such a shader yet, so those views draw the toon metals solid magenta. The normal picture is unaffected.
▲ 0↑ born
backing path · metalsMaterials.package/materials/polishedGold.material
Problems
Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.
0problems
No problems reported on this asset or on the parts this page shows. Parts it leaves out are not counted here.
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up
agent_score is exposed.usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor
+ quality × 0.35
+ performance × 0.25
± compat factor
Usability ratings
Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".
—%no reports yet
Sign in to report whether this part worked for you.
Discussion
Scoped to this part · feeds back into the world's score.
0comments
Sign in to post.sign in
No comments yet. Be the first.