masonryMaterials
Version 2.0.0. Depends on materialLibraryKit 1.3.1** (stated in the package's own dependency entry, and installed with it automatically; nothing else is installed).
masonryMaterials: Brick and Mortar
Version 2.0.0. Depends on materialLibraryKit 1.3.1 (stated in the package's own dependency entry, and installed with it automatically; nothing else is installed).
30 seamless, physically based masonry and building materials (brick, concrete, plaster, tile, roofing and street surfaces, plus toon, hand-painted and pixel-art sets) for the materialLibraryKit material library. Every material answers to one name, and every material shows at real size on any box, plane or model: a 1 m cube in brick shows about 13 courses, a 3 m wall about 40, a 10 cm cube about one, with no UV setup. Swapping a wall from red brick to toon brick or pixel brick is a change of one name.
Texture memory: 52.8 MB for all 30 (GPU, mipmaps included, every texture counted once), 63.1 MB with the 30 reference pictures and the board frame the gallery shows. The largest material is 3.0 MB.
Install and use
Install masonryMaterials from ZeroMind (search "masonryMaterials" or "Brick and Mortar"). It lands at /source/masonryMaterials.package, and materialLibraryKit 1.3.1, the shared material library it is built on, comes with it in the same install under /source/deps/. Nothing else is installed and there is no setup code: every material appears in the library's list, picker and swatch gallery on every player's machine.
Then, in a brand-new world, run this from a script or the console (execute):
local Materials = require("~materialLibraryKit.Materials")
-- a plain 1 m cube and a 3 m wall: bricks keep their real size on both
local cube = entity.spawn("brickCube", { components = { Model = { model = "cube" } } })
cube.localPosition = { -2, 0.5, 4 }
local wall = entity.spawn("brickWall", { components = { Model = { model = "cube" } } })
wall.localPosition = { 1, 1.5, 4 }
wall.localScale = { 3, 3, 0.2 }
local cubeModel = cube.component.get("Model")
local wallModel = wall.component.get("Model")
cubeModel.material = Materials.get("brickRunning").material
wallModel.material = Materials.get("brickRunning").material
-- the same wall in a cartoon world, or a retro one: only the name changes
wallModel.material = Materials.get("toonBrick").material
wallModel.material = Materials.get("pixelBrick").material
-- every roof, by name
for _, m in Materials.list({ collection = "masonry", kind = "roof" }) do
print(m.id, m.style, m.tileSize, m.textureKB)
end
Materials.get(name) returns the material's entry (nil for an unknown name), and its material goes on any Model. The library's Materials.apply(object, name) does the same in one call, records which material the object wears and shares that choice with every player (see Multiplayer); Materials.clear(object) puts back what it wore before. To remove the example: entity.despawn(cube.id) and entity.despawn(wall.id).
Real size on anything
The masonry shaders do not use a mesh's UVs. They place the texture by where each point stands on its own object, in metres, so one texture repeat always covers the material's tileSize (the table below) whatever the object's size:
- Any size. A 1 m cube of
brickRunningshows 13⅓ courses of 75 mm, a 3 m wall 40, a 10 cm cube one or two. Stretching an object adds bricks rather than stretching them.cinderBlockshows 5 courses of 200 mm per metre andtileSubway13⅓ rows of 75 mm. - Any shape. Each face takes the projection it faces. A box face has exactly one; a sphere, cylinder or model blends the nearest two or three over a narrow band, which reads as a soft join on strongly curved surfaces.
- Stuck to the object. The texture is measured from the object's origin along its own axes, so it moves and turns with the object. It is centred on the object's origin.
- Which way is up. On the four sides, the image's up is the object's +Y, so courses run level on an upright box. On the top face, the image's up is the object's -Z. To make a roof slab, take a flat box and tilt it about its X axis with its -Z end raised to the ridge: the courses run along the ridge and climb the slope.
- Lining up neighbours. Two separate objects line up their courses when their origins are a whole number of repeats apart. The gallery's walls and the street corner's house are single objects, so their courses run straight through.
- Roads.
roadLaneMarkingsis laid out around the object's origin: the dashed yellow centre line runs through the origin along the object's Z axis, with a 12 ft lane, a white edge line and an 8 ft shoulder on each side. A flat piece 12.19 m (40 ft) wide shows the whole road, and a wider piece repeats it.roadCrosswalkis centred the same way: a piece 3.66 m (12 ft) across shows one lane's three bars whole, and a wider piece repeats them lane by lane. Both drawasphalt's maps, so road pieces in different materials join without a change in the asphalt.
The gallery
To walk round every material, open the gallery scene in the package: in the shell run zero scene load masonryMaterials.MasonryGallery, or make it your world's start scene in .world_settings (startup_scene = "masonryMaterials.MasonryGallery"). All 30 stand on one ring around the spawn. Each has its own bay with a 2 x 2 m floor tile, a wall, and a cube, sphere, shader ball and cylinder standing side by side, all at real size. Its reference picture is framed on the wall beside it, and a plaque names it. The toolbar switches the lighting look for everyone (daylight, overcast, golden hour, moonlight, warm interior, studio). Materials opens the picker, which puts any material on whatever you click (in play) or have selected (in the editor), for every player. Each player arrives on a spot of their own, with the camera lifted to 4 m so the plaques stay readable.
To put the gallery in a scene of your own instead, add it in that scene's build.luau, with the player's spawn near the origin:
local g = entity.spawn("Gallery")
g.component.add("SwatchGallery", {})
g.component.add("MasonryShowcase", {})
The world this package comes from, "Brick and Mortar: The Masonry and Building Material Collection", opens straight into the gallery, with a street corner built from these materials beyond the ring.
The materials
Every material is tagged category = masonry, with its kind (brick, concrete, block, plaster, render, tile, roof, asphalt, road marking, paving), its style, tileSize (metres covered by one texture repeat), roughness and metallic ranges, textureKB (GPU texture memory, mipmaps included), animated = false, and search words. More tags make the list easy to filter:
- Kind and style: the
kindandstylevalues are tags too (brick,roof,realistic,toon,pixel,stylised; andhand-paintedon the hand-painted wall). - Tile size:
tile-<metres>m, for exampletile-0.9m. - Finish (roughness):
glossy(median roughness under 0.25),satin(under 0.6) orrough. Tiles are judged by their glaze, not their grout. - Memory weight:
textures-tiny(under 128 KB),textures-light(under 1.5 MB),textures-medium(under 2.5 MB) ortextures-heavy(up to 3 MB). - Metal and animation:
non-metallicandnot-animatedon every material. Metallic is 0 everywhere.
Some examples:
Materials.list({ collection = "masonry", kind = "brick" })Materials.list({ collection = "masonry", tag = "glossy" })Materials.list({ collection = "masonry", style = "toon" })Materials.list({ collection = "masonry", maxTextureKB = 1024 })Materials.list({ collection = "masonry", search = "herringbone" })
How to read the table. Textures lists albedo / normal / mask sizes in pixels. The mask packs ambient occlusion, roughness and metalness; - means the material does not use that map. Memory is the material's own GPU texture memory. Seam is the 4 x 4 seam score at real size and shimmer the 30 m shimmer score, both measured on 2026-10-24 on the desktop engine with materialLibraryKit 1.3.1 (see "Checked").
| Name | Material | Kind, style | Tile (m) | Real sizes | Roughness | Textures (memory) | Tags: finish, weight, tile | Seam / shimmer |
|---|---|---|---|---|---|---|---|---|
| Brick | ||||||||
brickRunning | Red brick, running bond | brick, realistic | 0.9 | UK bricks 215 x 65 mm, 10 mm joints; 4 bricks and 12 courses per repeat | 0.78–0.93 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-0.9m | 5.03 / 2.95 |
brickFlemish | Brown Flemish bond brick | brick, realistic | 1.35 | UK bricks: 225 mm stretchers and 112.5 mm headers alternating in every course, 75 mm courses; 4 bond periods and 18 courses per repeat | 0.76–0.94 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-1.35m | 0.70 / 4.67 |
brickEnglish | Buff English bond brick | brick, realistic | 0.9 | UK bricks, alternate courses of 225 mm stretchers and 112.5 mm headers, 75 mm courses; 4 stretchers and 12 courses per repeat | 0.8–0.93 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-0.9m | 1.26 / 1.21 |
brickCommon | Common bond brick | brick, realistic | 0.8128 | US modular bricks 7 5/8 x 2 1/4 in, 3/8 in joints (8 in pitch, 3 courses to 8 in); a header course every sixth course; 4 bricks and 12 courses per repeat | 0.78–0.93 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-0.81m | 5.12 / 2.57 |
brickStack | Whitewashed stack bond | brick, realistic | 0.9 | UK bricks 215 x 65 mm with 10 mm joints, stacked (vertical joints aligned): 225 x 75 mm module; 4 bricks and 12 courses per repeat | 0.88–0.91 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-0.9m | 0.88 / 0.14 |
brickYellowStock | Yellow stock brick | brick, realistic | 0.95 | imperial stock bricks 9 x 3 in with 3/8 in lime joints (about 237 x 79 mm module); 4 bricks and 12 courses per repeat | 0.84–0.96 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-0.95m | 0.97 / 1.67 |
| Concrete, block, plaster and render | ||||||||
concreteSmooth | Smooth concrete | concrete, realistic | 2 | cast in-situ concrete, 2 m repeat; small air holes 1 to 4 mm | 0.71–0.76 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-2m | 1.36 / 0.21 |
concreteBoardFormed | Board-formed concrete | concrete, realistic | 1.2 | 150 mm horizontal board imprints, 8 boards per repeat, butt joints staggered | 0.76–0.83 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-1.2m | 1.52 / 0.26 |
concreteStained | Stained concrete | concrete, realistic | 2 | 2 m repeat; run-off streaks 5 to 40 cm wide | 0.76–0.84 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-2m | 1.25 / 2.36 |
concreteCracked | Cracked concrete | concrete, realistic | 2 | 2 m repeat; cracks 1 to 6 mm wide, a few spalled patches | 0.8–0.86 | 1024 / 1024 / 512 (3.0 MB) | rough textures-heavy tile-2m | 0.72 / 0.83 |
cinderBlock | Cinder block | block, realistic | 1.2 | blocks 390 x 190 mm, 10 mm joints, running bond; 3 blocks and 6 courses per repeat | 0.87–0.92 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-1.2m | 2.60 / 0.65 |
plaster | Interior plaster | plaster, realistic | 1 | 1 m repeat; gentle trowel undulation | 0.84–0.87 | 512 / 512 / 512 (1.0 MB) | rough textures-light tile-1m | 1.25 / 0.06 |
stucco | Sand-finish stucco | render, realistic | 1 | 1 m repeat; sand grains 0.5 to 1.5 mm | 0.89–0.91 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-1m | 1.32 / 0.13 |
| Tiles | ||||||||
tileSubway | White subway tile | tile, realistic | 0.6 | glazed tiles 75 x 150 mm with 2 mm grout, running bond; 4 tiles and 8 rows per repeat | 0.05–0.9 | 512 / 1024 / 512 (2.0 MB) | glossy textures-medium tile-0.6m | 0.21 / 0.08 |
tileSquareGrid | Square floor tile | tile, realistic | 1.2 | 300 mm porcelain tiles with 3 mm grout in a square grid; 4 x 4 tiles per repeat | 0.39–0.56 | 512 / 1024 / 512 (2.0 MB) | satin textures-medium tile-1.2m | 0.56 / 0.71 |
tileHexMosaic | Hexagon mosaic tile | tile, realistic | 0.7 | hexagons 25 mm across flats with 2 mm grout; 26 x 30 hexagons per repeat | 0.16–0.91 | 1024 / 1024 / 512 (3.0 MB) | glossy textures-heavy tile-0.7m | 2.08 / 0.04 |
tileCheckerboard | Checkerboard tile | tile, realistic | 1.2 | 300 mm glazed tiles with 2 mm grout; 4 x 4 tiles per repeat | 0.07–0.11 | 512 / 1024 / 512 (2.0 MB) | glossy textures-medium tile-1.2m | 0.09 / 5.39 |
terracottaTiles | Terracotta floor tile | tile, realistic | 1.2 | 300 mm handmade tiles with 8 mm sanded grout; 4 x 4 tiles per repeat | 0.75–0.95 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-1.2m | 0.41 / 1.93 |
| Roofs | ||||||||
roofAsphaltShingles | Asphalt shingles | roof, realistic | 1 | three-tab shingles with 333 mm tabs, 125 mm exposure, each course offset half a tab; 3 tabs and 8 courses per repeat | 0.89–0.95 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-1m | 1.23 / 0.79 |
roofSlate | Slate roof | roof, realistic | 2 | natural slates 250 mm wide, 250 mm exposure (575 mm slates, 75 mm headlap), courses offset half a slate; 8 slates and 8 courses per repeat | 0.59–0.71 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-2m | 0.58 / 1.63 |
roofClayPantiles | Clay pantiles | roof, realistic | 1 | S-profile pantiles, 200 mm cover width, 250 mm gauge; 5 tiles across and 4 courses per repeat | 0.7–0.78 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-1m | 1.32 / 2.98 |
roofThatch | Thatch | roof, realistic | 1 | water reed thatch, butt ends 4 to 8 mm across; 1 m repeat | 0.87–0.94 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-1m | 1.62 / 1.98 |
| Street | ||||||||
asphalt | Road asphalt | asphalt, realistic | 1.219 | dense asphalt, aggregate 2 to 12 mm; a 4 ft (1.2192 m) repeat, so 10 repeats span a 40 ft lane-marking repeat | 0.8–0.92 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-1.22m | 1.15 / 1.60 |
roadLaneMarkings | Road lane markings | road marking, realistic | 12.19 | US two-lane road: two 12 ft (3.66 m) lanes and 8 ft (2.44 m) shoulders across one 40 ft (12.19 m) repeat; 4 in yellow centre line dashed 10 ft on, 30 ft off; 6 in solid white edge lines | 0.55–0.92 | asphalt's maps (0 (shares asphalt's 2.0 MB)) | rough textures-medium tile-12.19m | 1.41 / 2.18 |
roadCrosswalk | Road crosswalk | road marking, realistic | 3.658 | white bars 24 in (0.61 m) wide with 24 in gaps and 10 ft (3.05 m) long, parallel to traffic; one repeat is one 12 ft lane by 12 ft | 0.55–0.92 | asphalt's maps (0 (shares asphalt's 2.0 MB)) | rough textures-medium tile-3.66m | 0.44 / 3.73 |
pavingSlabs | Sidewalk slabs | paving, realistic | 3.048 | 5 ft (1.524 m) square panels with tooled control joints and a broom finish; 2 x 2 panels per repeat | 0.78–0.87 | 1024 / 1024 / 512 (3.0 MB) | rough textures-heavy tile-3.05m | 7.95 / 0.52 |
pavingBrickHerringbone | Herringbone pavers | paving, realistic | 1.2 | clay pavers about 200 x 100 mm with 6 mm sand joints, 45 degree herringbone; 1.2 m repeat | 0.78–0.94 | 512 / 1024 / 512 (2.0 MB) | rough textures-medium tile-1.2m | 0.97 / 3.80 |
| Stylised | ||||||||
toonBrick | Toon brick | brick, toon | 1 | chunky cartoon bricks, 4 across and 8 courses per 1 m repeat | 0.9 | 256 / - / - (85 KB) | rough textures-tiny tile-1m | 3.31 / 4.77 |
handPaintedPlasterBrick | Hand-painted plaster and brick | plaster, stylised | 2 | 2 m repeat; bricks 25 x 8 cm in the exposed patches | 0.88 | 512 / 512 / - (683 KB) | hand-painted rough textures-light tile-2m | 0.71 / 1.14 |
pixelBrick | Pixel-art brick | brick, pixel | 1 | 32 x 32 pixels per 1 m repeat; bricks 16 x 8 pixels | 0.9 | 32 / - / - (1 KB) | rough textures-tiny tile-1m | 17.02 / 0.70 |
Texture memory
- The whole collection: 52.8 MB of GPU texture memory, mipmaps included. That is 79 textures, each counted once.
- Counted per material, as
Materials.listreports it (textureKB), the 30 add up to 56.8 MB. The difference is thatroadLaneMarkingsandroadCrosswalkeach listasphalt's 2.0 MB of maps again. - Reference pictures: 10.0 MB (30 pictures at 512 px), plus 0.3 MB for the one frame texture all 30 boards share. They are only loaded where the gallery shows them.
- Everything together: 63.1 MB, about a sixth of the library's 384 MiB budget for low-end devices.
- Texture sizes (albedo / normal / mask, in pixels):
- 512 / 1024 / 512 for most realistic materials (2.0 MB);
- 1024 / 1024 / 512 for
concreteCracked,tileHexMosaicandpavingSlabs, whose cracks, grout and joints need the colour detail (3.0 MB); - 512 / 512 / 512 for
plaster(1.0 MB); - 512 / 512 / - for
handPaintedPlasterBrick(683 KB); - 256 / - / - for
toonBrick(85 KB); - 32 / - / - for
pixelBrick(1 KB).
- Within the web limits: every material binds at most 4 sampled textures (the web limit is 9) and no storage buffers, and nothing is over 1024 px.
- Compression: textures are UASTC, transcoded to BC7 on desktop and ASTC on phones.
How they were made
- Baked procedurally in Luau by
MasonryBaker,MasonryCatalogand the recipe modules (BrickRecipes,ConcreteRecipes,TileRecipes,RoofRecipes,PavingRecipes,StylisedRecipes).MasonryBakeris Bedrock's StoneBaker (itself Heartwood's periodic baker, MIT) with masonry layouts added: rectangle layouts that know each brick's edges, and rotated boxes for herringbone.- Every map is periodic over one repeat, so it tiles with no seam by construction, and is drawn at real scale (1 unit = 1 m).
require("~masonryMaterials.MasonryRecipes").bakeAll()re-bakes the lot.
- Real-size placement. The shared shader module
masonryProjectionplaces textures in metres on each object. It follows Bedrock'sstoneTriplanar(MIT), with a narrow blend so box faces take one projection.masonrySurface(physically based),roadPaintandtoonMasonryall use it. - Every bond is a real bond. Bricks are laid as rectangles of the real brick plus its joint, and each repeat holds a whole number of bond periods both ways, so courses and perpends line up across the edge.
brickRunning: red running bond, half-brick offset, UK 225 x 75 mm module.brickFlemish: brown Flemish bond. Stretchers and headers alternate in every course, each header centred on the stretcher below, the headers burnt darker.brickEnglish: buff English bond. Courses of stretchers and courses of headers alternate, with a queen closer setting the header course back a quarter brick.brickCommon: American common bond. US modular brick, five running-bond courses, then a course of headers.brickStack: whitewashed stack bond. Perpends run in straight columns, and limewash covers brick and mortar alike, worn thin on the arrises.brickYellowStock: weathered yellow London stock. Imperial handmade bricks (9 x 3 in, 3/8 in lime joints) with soot and dark flashes.
- Roads at real US dimensions (MUTCD): 12 ft lanes, 8 ft shoulders, a 4 in yellow centre line dashed 10 ft on and 30 ft off, 6 in white edge lines, and crosswalk bars 24 in wide with 24 in gaps, 10 ft long. The paint is computed in the shader over
asphalt's maps, smoothed over one screen pixel. So a dash is sharp at 1 m, filters calmly at 30 m, and costs no texture memory. - Physically based.
- Colour maps carry no painted-in light or shadow. Joints, grout, cracks and course steps darken through the ambient-occlusion channel and the normal map.
- Every surface is non-metallic: metallic is 0 everywhere.
- Roughness follows the finish:
- glazed subway and checker tiles: 0.05–0.11 on the glaze;
- the hexagon mosaic's satin glaze: from 0.16;
- porcelain floor tile: 0.39–0.56;
- slate: 0.59–0.71;
- brick, concrete, block, render, terracotta, shingles and thatch: 0.7–0.96;
- grout and mortar: 0.9 and up.
- Normal maps use the green-up convention the engine reads. Joints, grout and gaps are drawn low, so they read as sunk; the test suite proves the direction on a synthetic groove.
- Reference pictures first. Every material has a reference picture (
references/<id>), generated from the prompt in its catalog entry before the material was drawn. Each material was then compared with its picture side by side: one repeat lit beside the unlit picture, the material's mean colour measured against the picture's, and finally in its gallery bay with the picture hung beside it.
Checked
Every material passes the library's checks (materialLibraryKit 1.3.1, 2026-10-24, desktop engine):
- Seamless repeated 4 x 4 at real size. A plain box face exactly 4 repeats wide and tall is rendered straight on in the albedo pass (lit for the self-shading toon brick).
- The jump in brightness across each repeat line is compared with the jumps inside a repeat, using the library's own seam statistics and thresholds. The seam score is the jump across repeat lines divided by the jump inside a repeat.
- A render passes when the boundary jump is at most 3 code values, or the score is at most 2, or the boundary jump is no bigger than 1.1 × the strongest edges inside a repeat. Separately, the library's
Checks.seamsconfirms every texture's opposite edges match. - Some scores are above 2 and pass on the last rule, because their own joints are as strong inside a repeat as across one:
pixelBrick(17.0),pavingSlabs(7.95, whose tooled joints fall on the repeat),brickCommon(5.12),brickRunning(5.03),toonBrick(3.31),cinderBlock(2.60) andtileHexMosaic(2.08). - The library's own
Checks.seamsrender assumes a 4 m plane holds 4 repeats, which is only true of materials whose repeat is 1 m now that size is real. So the package's tests do this render at each material's true repeat instead.
- Shimmer at 30 m. Near (about 1.5 m) and far (30 m, grazing) views. The shimmer score is how many code values the far view moves under a half-pixel camera shift, and it fails above 6. The highest are
tileCheckerboard(5.39),toonBrick(4.77) andbrickFlemish(4.67); every other material is under 4. - Real size measured. On plain engine cubes, the course spacing is measured from the rendered normal pass:
brickRunningis 75 mm on a 1 m cube and on a 3 m wall;cinderBlockis 200 mm andtileSubway75 mm on a 1 m cube;- each is within 6%, and a 10 cm cube crosses one or two bed joints.
- Diagnostic views, texture memory cross-checked against what the renderer holds, and the web budget (
Checks.budget: no warnings for any material).
The package's test suite (29 tests) reruns all of these. It also covers:
- the exact 30 names, every tag, the styles, the filters and the costs;
- the physical ranges, plausible albedos and the normal direction;
- the tile sizes holding whole bricks and tiles, and the road markings sharing the asphalt;
- applying a material to a world-built object, swapping to toon and clearing through the shared channel, and the picker;
- the gallery with all 30 on one ring, every material on every sample shape beside its reference, and the stylised looks;
- the dependency on materialLibraryKit 1.3.1, the scene, the versions and this README.
Each test runs inside the library's Sync.isolate(), so nothing it does reaches other players. When the gallery is not standing, the suite stands one up and removes it again. To run it:
asset.resolve("masonryMaterials.tests.masonryMaterials", "testSuite"):run()
Multiplayer
- Applied materials are shared.
Materials.applygoes through the library's sharedmaterialschannel, so a material one player puts on an object every player's machine holds shows on every machine, and players who join later get it too. Objects every machine holds are the gallery's swatches, a scene's own objects, and asyncedobject spawned in play. The picker applies the same way. - Lighting looks are shared the same way.
- Script-made objects stay local. An object a script spawns in edit mode, like the cube and wall in the first example, exists only on the machine that ran the script, so only that machine sees it, whichever way its material is set.
- Gallery pieces are local. The swatches and reference boards are built on each machine.
On the web
- Within the browser's limits. Every material passes the library's web budget with no warnings: at most 4 textures per draw against a browser limit of 9, no storage buffers, at most 3 MB per material, every texture GPU-compressed (UASTC), and none in a format browsers cannot filter. The paint on the two road materials is computed, so it needs no large texture.
- The gallery was made lighter to draw in 2.0.0. In a browser editor tab, 1.0.0's gallery was reported at about 12 frames per second, where an empty world ran at 60. What changed, measured on the desktop engine with the gallery in view from the spawn:
- Each reference board was four objects: a holder, a frame, the picture, and a text caption with its own material and a script running every frame. It is now two objects that cast no shadow: the picture, and one frame panel whose texture carries the frame and the REFERENCE caption, shared by all 30 boards. The gallery went from 454 to 394 objects, and from 92 text labels with per-frame scripts to 62 (the library's own name and fact plaques). That removes 30 materials and 60 shadow casters from the scene.
- The frame is now unlit, like the pictures, so it costs no lighting work.
- The masonry shaders were measured for per-pixel cost: putting the engine's plain material on all 192 masonry objects changed the per-pixel shading pass by under 4% (1.04 ms against 1.00 ms on this machine). The shaders are not where the time goes, so they are unchanged, and every material looks exactly as before.
- Not measured in a browser. This release was prepared in the desktop engine, which cannot open a browser tab, and no browser was connected to measure with. Whether the gallery now holds 30 frames per second in a browser editor tab has not been confirmed. The library's own gallery reads its frame rate on every player's machine: with a browser player in the world,
require("~materialLibraryKit.Gallery").requestTour()reports it inSync.heard(). - What to expect in a browser:
- For about 30 seconds after the world opens, the gallery and the street corner stay unbuilt while errors pile up in the log; then they build (gh#20822).
- Every time the engine starts there is a magenta ERROR line in the log (gh#20949).
Known limits
- Curved surfaces blend projections. On a sphere, cylinder or rounded model the texture blends between neighbouring projections over a narrow band, which shows as a soft join where bricks from two directions meet. Box faces and planes take a single projection.
- US road markings only. The lane markings follow the US MUTCD (yellow centre line, 40 ft cycle).
- The checkerboard is the closest to the shimmer limit (5.39 against 6), because hard black against white is what it is.
- The toon brick has no diagnostic channels.
toonMasonrylights itself, so the library's albedo, roughness and metallic views draw it magenta. Its final and normal views are normal. - The gallery is heavy in the editor's play mode. With the full ring standing (about 360 entities), the editor spends 30–110 ms on some frames sending the gallery's swatches over the network. The library's own gallery scene does the same with no masonry content. This is reported to materialLibraryKit; the materials themselves cost nothing per frame.
- The download is larger than the texture memory. Each texture keeps a source image beside its GPU data, because materialLibraryKit measures texture cost from the source image.
Open engine issues
gh#N is issue N at github.com/OrigoZero/zero.
- gh#20822: in a browser, the gallery and the street corner stay unbuilt for about 30 seconds and errors pile up in the log meanwhile.
- gh#20949: every time the engine starts there is a magenta ERROR line.
- Shader include race on first install (reported to ZeroMind as issue 01M5QZ1QA4XQ90RN2MDK9DWSX9; no GitHub number yet): right after installing, the log can show a few
#include of unknown shader module "~.shaders.masonryProjection"errors. The shaders compile moments later and every material draws correctly; nothing needs doing. - gh#19114: two-player behaviour can't be tested inside one engine. Shared materials are checked through the library's shared channel.
- gh#1889: no
asset.materialCollection.*namespace yet, so the materials are reached throughMaterials.*. - gh#19414: the engine's normal-map green convention is undocumented. These maps are green-up.
Version history
-
2.0.0 (2026-10-24), on materialLibraryKit 1.3.1. This is the first version number that stands for one fixed collection; install this one. It holds:
- the 30 materials, under the names in the table above;
- real size on any box, plane or model, with no UV setup;
- their 30 reference pictures, the gallery scene, the street corner and the test suite (29 tests);
- a lighter gallery: each reference board is a picture and one shared frame panel carrying the REFERENCE caption, with no text label or shadow of its own (see "On the web");
- a dependency entry in
package.yamlthat names materialLibraryKit version 1.3.1.
-
1.0.0 (2026-10-24), withdrawn. The number 1.0.0 was uploaded several times that day with different contents, so two copies called 1.0.0 may not match. The first uploads had 32 materials under older names, one texture repeat per face of a primitive, and a dependency with no version. Later uploads had the 30 names and real size. If you installed any 1.0.0, uninstall it and install 2.0.0. Scripts written against the first uploads need these names changed:
Old name (first 1.0.0) Name now redBrickbrickRunningflemishBondbrickFlemishenglishBondbrickEnglishamericanBondbrickCommoncharcoalStackBond,whitewashedStackBondbrickStacklondonStockbrickYellowStocksmoothConcrete,boardFormedConcrete,stainedConcrete,crackedConcreteconcreteSmooth,concreteBoardFormed,concreteStained,concreteCrackedinteriorPlaster,sandStuccoplaster,stuccosubwayTile,floorTileGrid,hexMosaic,checkerTile,terracottaTiletileSubway,tileSquareGrid,tileHexMosaic,tileCheckerboard,terracottaTilesasphaltShingles,slateRoof,clayPantiles,thatchroofAsphaltShingles,roofSlate,roofClayPantiles,roofThatchroadAsphalt,laneMarkings,zebraCrossingasphalt,roadLaneMarkings,roadCrosswalksidewalkSlabs,herringbonePaverspavingSlabs,pavingBrickHerringbonehandPaintedPlasterhandPaintedPlasterBrickreclaimedBrick,toonRoofTiles,concretePaversremoved
Scoped to this part · feeds back into the world's score.