◐
material · drop-in viewer
asset⌬ materialmaterialprimary: mat.yaml·part ofpackage toonMaterials.package·originates fromworld f17aab57-4…
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.
⌬ Metadata
description
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.
20+items
# toonSurface
The one surface shader every toonMaterials material draws with: cel shading for the basics and the flat palette (the sun and lamps cut into `bands` flat bands, a lifted shadow tinted by `shadow_tint`, a thin hard rim, an optional hard highlight band and a sky and ground reflection split for metal), soft-edged bands for the hand-painted set, and a four-stop colour ramp for the gradient set (with self-lit breathing glow and drifting toon water ripples). The shared look (`bands`, `shadow_lift`, `shadow_tint`, `rim`) is set for every material at once by `ToonLook`. Two texture slots: albedo and an optional normal map. Base: organicMaterials' toonOrganic (MIT).
▲ 0↑ born
▲ 0↑ born
▲ 0↑ born
# toonMaterials: Ink and Gouache
**24 toon and cel-shaded materials for the Swatchbook material library (materialLibraryKit), all one cosy cartoon style: the same light bands, one shared palette, one ink outline colour and weight, so a brick wall, a grass path, a wooden door and a tree in one scene read as one cartoon.**
Version 1.0.10. Depends on materialLibraryKit 1.4.2 (Swatchbook, the current material library) and nothing else; installing this package brings the library along. Once installed, every toon material is in the library's list, picker and swatch gallery on every player's machine, with no setup code.
## Guides in this package
Two guides ship inside the package, so every world that installs it has them. Open them in the engine's guides by their full path (the short name alone does not open, engine issue #22286):
- **How to make my game look like a cartoon: cel shading with ink outlines** (`toonMaterials.package/guides/makeYourGameLookLikeACartoon`): what the kit is, putting a toon material on something, finding materials by family and swapping them, how the ink outline works and what its settings do, how it behaves with several players, and how it combines with the toon versions in the metals, sci-fi, fantasy, organic, synthetics and translucent collections.
- **Make a cartoon game scene from an empty world: a cel-shaded village with ink outlines, step by step** (`toonMaterials.package/guides/buildACelShadedCartoonVillage`): from an empty world to a small cartoon level with two characters, props and ground, all cel-shaded with ink outlines; then the whole village swapped between the four families with one word, and the bands and outlines turned up or down for every player.
ZeroMind search does not find guides inside a package yet (ZeroMind#3099, engine #22181): read them from the installed package, or search this world's guides from the engine.
## Install and put the first material on a cube
Install **toonMaterials** from ZeroMind (search "toonMaterials" or "Ink and Gouache"). Then, in an empty world, from the console or any script:
```luau
local Materials = require("~materialLibraryKit.Materials")
local ToonInk = require("~toonMaterials.ToonInk")
-- synced: the cube exists for every player, so every player sees its material and its ink
local cube = entity.spawn("toonCube", { synced = true, components = { Model = { model = "cube" } } })
cube.localPosition = { 0, 1, 3 }
assert(Materials.apply(cube, "toonMetal")) -- cel-shaded riveted steel, for every player
assert(ToonInk.set(cube, true)) -- the dark ink outline, for every player
```
`Materials.apply` and `ToonInk.set` return `ok, err`; the `assert` stops with the reason instead of leaving the cube grey. To take it away again: `Materials.clear(cube)`, `ToonInk.set(cube, false)`, `entity.despawn(cube.id)`. Swap the look by changing one word: `Materials.apply(cube, "toonBrick")`.
## Use it together with the material library
Installing toonMaterials brings the material library (materialLibraryKit 1.4.2, the current release) with it, so the toon set works on its own. To add other material collections, or the library's own guides, tools and gallery, install **materialLibraryKit** from ZeroMind as well, before or after toonMaterials:
```bash
zero zeromind installAsset aafbaae5-5d94-4661-b8d4-688eeed11d1b # toonMaterials
zero zeromind installAsset 0d7f3e76-0699-44fd-b0ac-2cb37822b648 # materialLibraryKit
```
Either order leaves one material library in the world, the current one, and `require("~materialLibraryKit.Materials")` answers with it; the toon materials appear in it beside its calibration shelf and apply as above. One thing to do when toonMaterials is already in the world and you install materialLibraryKit on top of it: reload the world once afterwards. Until you do, the library reports problems for some of its own calibration materials and lists fewer of them, and an outline that another player switches on or off is not picked up on your machine (engine issue #22328, see "Known limits" and "Fresh install"). Check the library with:
```luau
local Materials = require("~materialLibraryKit.Materials")
for _, c in Materials.collections() do print(c.name, c.version, c.count) end -- calibration 1.4.2 20, toon 1.0.7 24
```
Up to 1.0.5 this package pinned materialLibraryKit 1.3.1. A world that installed one of those releases and then the current library holds two packages named `materialLibraryKit`, and the engine refuses to choose between them, so `require("~materialLibraryKit.Materials")` fails. Update toonMaterials to the current release (`zero zeromind update /zero/source/toonMaterials.package`) or remove the old library copy, so one library is left.
## Texture memory
**26.7 MB for all 24 materials** (GPU memory, mipmaps included; UASTC, which the engine turns into BC7 on desktop and ASTC on phones). The flat set, the water and the glow use no textures at all. The 24 reference pictures the gallery hangs add 8.0 MB (34.7 MB with them). The heaviest single material is 2.7 MB, far inside the web's per-material limit (24 MiB), and every one passes the library's web check (`Checks.budget`): 2 sampled textures each (the web limit is 9), no storage buffers, nothing over 1024 px.
## The materials
Every material is tagged `toon`, `cartoon`, `stylised` and `outline-ready`, plus what it is (category and kind), its style family (`cel`, `flat`, `hand-painted` or `gradient`, and `family-cel` / `family-flat` / `family-painted` / `family-gradient`), its tile size (`tile-<metres>m`), `glowing` or `not-glowing`, `animated` (with what moves) or `not-animated`, how many textures it binds (`0-textures`, `1-texture`, `2-textures`) and their cost (`textures-none`, `textures-light`, `textures-medium`, `textures-heavy`), `cel-shaded` and `3-bands` (the shared default) on the banded families, `gradient-mapped` on the ramps, `painted light` or `no baked light`, `seamless`, `metallic` or `non-metallic`, and search words.
Tile is the metres one texture repeat covers (1 unit = 1 m). Seamless means `Checks.seams`, tiled 4 x 4, passes on the render and on every texture's opposite edges: all 18 textured and patterned materials pass (the 5 flat colours and the glow have no pattern to tile).
| Name | Material | Kind, family | Tile | Glows | Moves | Textures (memory) | Real size |
|---|---|---|---|---|---|---|---|
| `toonMetal` | Toon metal | steel plate, cel | 1 m | no | no | albedo + normal 512 (683 KB) | plates 500 x 250 mm, rivets 22 mm on a 125 mm pitch |
| `toonWood` | Toon wood | timber, cel | 1 m | no | no | albedo + normal 512 (683 KB) | grain lines 4 to 8 mm wide, knots 30 to 60 mm |
| `toonStone` | Toon stone | flagstone, cel | 2 m | no | no | albedo + normal 1024 (2.7 MB) | flagstones 250 to 600 mm across, joints 25 mm |
| `toonMasonry` | Toon masonry blocks | ashlar, cel | 2 m | no | no | albedo + normal 1024 (2.7 MB) | blocks 400 to 800 mm long on 333 mm courses, joints 20 mm |
| `toonBrick` | Toon brick | brick, cel | 1 m | no | no | albedo + normal 512 (683 KB) | bricks 215 x 65 mm, mortar 10 mm (a standard brick on 75 mm courses) |
| `toonPlanks` | Toon planks | planks, cel | 2 m | no | no | albedo + normal 1024 (2.7 MB) | boards 180 mm wide, 0.6 to 1.4 m long, gaps 8 mm, nails 12 mm |
| `toonGrass` | Toon grass | grass, cel | 2 m | no | no | albedo + normal 1024 (2.7 MB) | tufts 60 to 140 mm, blades 8 mm |
| `toonDirt` | Toon dirt | dirt, cel | 2 m | no | no | albedo + normal 1024 (2.7 MB) | pebbles 15 to 60 mm, patches 200 to 500 mm |
| `toonSand` | Toon sand | sand, cel | 2 m | no | no | albedo + normal 1024 (2.7 MB) | ripples on a 125 mm spacing, specks 5 to 12 mm |
| `toonRock` | Toon rock | rock, cel | 2 m | no | no | albedo + normal 1024 (2.7 MB) | facets 200 to 700 mm, cracks 12 to 30 mm |
| `flatRoofRed` | Flat roof red | roof red, flat | 1 m | no | no | none (0) | one colour, no texture |
| `flatLeafGreen` | Flat leaf green | leaf green, flat | 1 m | no | no | none (0) | one colour, no texture |
| `flatWallCream` | Flat wall cream | wall cream, flat | 1 m | no | no | none (0) | one colour, no texture |
| `flatWaterTeal` | Flat water teal | water teal, flat | 1 m | no | no | none (0) | one colour, no texture |
| `flatTrunkBrown` | Flat trunk brown | trunk brown, flat | 1 m | no | no | none (0) | one colour, no texture |
| `paintedGrass` | Hand-painted grass | grass, hand-painted | 2 m | no | no | albedo 1024 (1.3 MB) | brush strokes 40 to 120 mm, clumps 150 to 300 mm |
| `paintedStoneWall` | Hand-painted stone wall | stone wall, hand-painted | 2 m | no | no | albedo 1024 (1.3 MB) | stones 200 to 450 mm, joints 30 mm |
| `paintedPlanks` | Hand-painted planks | planks, hand-painted | 2 m | no | no | albedo 1024 (1.3 MB) | boards 200 mm wide, gaps 10 mm |
| `paintedRoofTiles` | Hand-painted roof tiles | roof tiles, hand-painted | 1 m | no | no | albedo 512 (341 KB) | tiles 200 mm wide on 125 mm rows |
| `paintedFoliage` | Hand-painted foliage | foliage, hand-painted | 1 m | no | no | albedo 512 (341 KB) | leaf clusters 100 to 220 mm |
| `rampBrass` | Two-tone brass | brass, gradient | 1 m | no | no | albedo + normal 512 (683 KB) | hammered dimples 30 to 60 mm |
| `rampFoliage` | Gradient foliage | foliage, gradient | 1 m | no | no | albedo + normal 512 (683 KB) | leaf clusters 90 to 200 mm |
| `rampWater` | Gradient water | water, gradient | 4 m | no | rippling, flowing | none (0) | ripple rings 0.3 to 1 m, foam lines 20 mm |
| `rampWarmGlow` | Warm glow | warm glow, gradient | 1 m | yes | pulsing | none (0) | glow cells 120 to 250 mm |
### Which set paints its light into the colour
Only the **hand-painted set** has shading painted into the colour: `paintedGrass`, `paintedStoneWall`, `paintedPlanks`, `paintedRoofTiles` and `paintedFoliage` (lit tops, shaded undersides and hollows, brush-stroke light, as hand-painted games do). Their light bands are softer and their shadow lighter, so the painted shade and the scene's light do not darken twice. Every other material carries flat palette colours and drawn ink lines only, with no light or shadow in its colour; the relief of the cel and gradient sets (bevels, facets, grooves, dimples, leaf domes) lives in a normal map, so the shared light bands follow it.
### Every material's tags
- `toonMetal`: toon, cartoon, stylised, metal, steel plate, cel, family-cel, cel-shaded, 3-bands, no baked light, tile-1m, outline-ready, ink outline, not-glowing, not-animated, 2-textures, textures-medium, tiled, seamless, metallic, steel, iron, plates, rivets, riveted, shiny
- `toonWood`: toon, cartoon, stylised, wood, timber, cel, family-cel, cel-shaded, 3-bands, no baked light, tile-1m, outline-ready, ink outline, not-glowing, not-animated, 2-textures, textures-medium, tiled, seamless, non-metallic, beam, grain, knots, door, post
- `toonStone`: toon, cartoon, stylised, stone, flagstone, cel, family-cel, cel-shaded, 3-bands, no baked light, tile-2m, outline-ready, ink outline, not-glowing, not-animated, 2-textures, textures-heavy, tiled, seamless, non-metallic, paving, path, slabs, courtyard
- `toonMasonry`: toon, cartoon, stylised, stone, ashlar, cel, family-cel, cel-shaded, 3-bands, no baked light, tile-2m, outline-ready, ink outline, not-glowing, not-animated, 2-textures, textures-heavy, tiled, seamless, non-metallic, masonry, blocks, castle, wall, cut stone
- `toonBrick`: toon, cartoon, stylised, masonry, brick, cel, family-cel, cel-shaded, 3-bands, no baked light, tile-1m, outline-ready, ink outline, not-glowing, not-animated, 2-textures, textures-medium, tiled, seamless, non-metallic, bricks, running bond, wall, chimney, house
- `toonPlanks`: toon, cartoon, stylised, wood, planks, cel, family-cel, cel-shaded, 3-bands, no baked light, tile-2m, outline-ready, ink outline, not-glowing, not-animated, 2-textures, textures-heavy, tiled, seamless, non-metallic, boards, floor, deck, nails, fence
- `toonGrass`: toon, cartoon, stylised, ground, grass, cel, family-cel, cel-shaded, 3-bands, no baked light, tile-2m, outline-ready, ink outline, not-glowing, not-animated, 2-textures, textures-heavy, tiled, seamless, non-metallic, lawn, meadow, hills, field, green
- `toonDirt`: toon, cartoon, stylised, ground, dirt, cel, family-cel, cel-shaded, 3-bands, no baked light, tile-2m, outline-ready, ink outline, not-glowing, not-animated, 2-textures, textures-heavy, tiled, seamless, non-metallic, earth, soil, path, track, pebbles, brown
- `toonSand`: toon, cartoon, stylised, ground, sand, cel, family-cel, cel-shaded, 3-bands, no baked light, tile-2m, outline-ready, ink outline, not-glowing, not-animated, 2-textures, textures-heavy, tiled, seamless, non-metallic, beach, desert, dunes, ripples, shore
- `toonRock`: toon, cartoon, stylised, ground, rock, cel, family-cel, cel-shaded, 3-bands, no baked light, tile-2m, outline-ready, ink outline, not-glowing, not-animated, 2-textures, textures-heavy, tiled, seamless, non-metallic, cliff, boulder, crag, mountain, cracks, grey
- `flatRoofRed`: toon, cartoon, stylised, flat colour, roof red, flat, family-flat, cel-shaded, 3-bands, no baked light, tile-1m, outline-ready, ink outline, not-glowing, not-animated, 0-textures, textures-none, non-metallic, red, roof, low poly, solid
- `flatLeafGreen`: toon, cartoon, stylised, flat colour, leaf green, flat, family-flat, cel-shaded, 3-bands, no baked light, tile-1m, outline-ready, ink outline, not-glowing, not-animated, 0-textures, textures-none, non-metallic, green, leaf, tree, bush, low poly, solid
- `flatWallCream`: toon, cartoon, stylised, flat colour, wall cream, flat, family-flat, cel-shaded, 3-bands, no baked light, tile-1m, outline-ready, ink outline, not-glowing, not-animated, 0-textures, textures-none, non-metallic, cream, wall, plaster, house, low poly, solid
- `flatWaterTeal`: toon, cartoon, stylised, flat colour, water teal, flat, family-flat, cel-shaded, 3-bands, no baked light, tile-1m, outline-ready, ink outline, not-glowing, not-animated, 0-textures, textures-none, non-metallic, teal, water, pond, lake, low poly, solid
- `flatTrunkBrown`: toon, cartoon, stylised, flat colour, trunk brown, flat, family-flat, cel-shaded, 3-bands, no baked light, tile-1m, outline-ready, ink outline, not-glowing, not-animated, 0-textures, textures-none, non-metallic, brown, trunk, tree, wood, low poly, solid
- `paintedGrass`: toon, cartoon, stylised, ground, grass, hand-painted, family-painted, cel-shaded, 3-bands, painted light, tile-2m, outline-ready, ink outline, not-glowing, not-animated, 1-texture, textures-medium, tiled, seamless, non-metallic, lawn, meadow, painted, painterly, brush strokes
- `paintedStoneWall`: toon, cartoon, stylised, stone, stone wall, hand-painted, family-painted, cel-shaded, 3-bands, painted light, tile-2m, outline-ready, ink outline, not-glowing, not-animated, 1-texture, textures-medium, tiled, seamless, non-metallic, wall, rubble, cobble, painted, painterly, brush strokes
- `paintedPlanks`: toon, cartoon, stylised, wood, planks, hand-painted, family-painted, cel-shaded, 3-bands, painted light, tile-2m, outline-ready, ink outline, not-glowing, not-animated, 1-texture, textures-medium, tiled, seamless, non-metallic, boards, painted, painterly, brush strokes, floor
- `paintedRoofTiles`: toon, cartoon, stylised, roof, roof tiles, hand-painted, family-painted, cel-shaded, 3-bands, painted light, tile-1m, outline-ready, ink outline, not-glowing, not-animated, 1-texture, textures-light, tiled, seamless, non-metallic, tiles, shingles, cottage, red, painted, painterly
- `paintedFoliage`: toon, cartoon, stylised, foliage, hand-painted, family-painted, cel-shaded, 3-bands, painted light, tile-1m, outline-ready, ink outline, not-glowing, not-animated, 1-texture, textures-light, tiled, seamless, non-metallic, leaves, tree crown, bush, hedge, painted, painterly
- `rampBrass`: toon, cartoon, stylised, metal, brass, gradient, family-gradient, gradient-mapped, colour ramp, no baked light, tile-1m, outline-ready, ink outline, not-glowing, not-animated, 2-textures, textures-medium, tiled, seamless, metallic, gold, shiny, polished, two-tone
- `rampFoliage`: toon, cartoon, stylised, foliage, gradient, family-gradient, gradient-mapped, colour ramp, no baked light, tile-1m, outline-ready, ink outline, not-glowing, not-animated, 2-textures, textures-medium, tiled, seamless, non-metallic, leaves, tree, bush, ramp
- `rampWater`: toon, cartoon, stylised, water, gradient, family-gradient, gradient-mapped, colour ramp, no baked light, tile-4m, outline-ready, ink outline, not-glowing, animated, rippling, flowing, 0-textures, textures-none, non-metallic, pond, lake, river, sea, ripples
- `rampWarmGlow`: toon, cartoon, stylised, glow, warm glow, gradient, family-gradient, gradient-mapped, colour ramp, no baked light, tile-1m, outline-ready, ink outline, glowing, emissive, animated, pulsing, 0-textures, textures-none, non-metallic, lantern, window, ember, warm, light, magic
### Vertex colours
A mesh that carries its own vertex colours (a procedural plant, a low-poly prop painted per vertex) can wear one cel material for all of them: make a material on `toonMaterials.shaders.toonSurface` with `vertex_tint = 1` and a white `base_color`, and every vertex's colour goes through the same light bands, rim and shadow tint as the library's own materials. `vertex_tint` is 0 on all 24 library materials, so meshes without vertex colours, or with colours meant for something else, are unaffected.
## Outlines and the shared look
**The ink outline.** Every material works with the ink outline on and with it off; the outline belongs to the object, not the material. Switching it on is all it takes, on a fresh start and on every player's screen: the package starts the outline on every machine that loads the world (see "How the outline starts" below), so there is nothing to prepare.
- `ToonInk.set(object, true / false)` switches one object's outline (and every part of it with a `Model`) for every player, late joiners included. `ToonInk.isOn(object)` reads it.
- A `ToonProp` component on a scene object outlines it from the scene file (`outline = true`) and maps its toon material by world position at its real tile size (`worldScale = true`), so a cube stretched into a 6 m wall shows its bricks at real size on every face. The toon corner is built this way.
- `ToonInk.add(object)` outlines on this machine only (for local objects such as the gallery's swatches).
The outline is an inverted hull drawn by the `toonInk` render feature: depth-tested against the scene, so a line never shows through a wall in front of it, and pushed out by the ink weight in real centimetres (3 cm by default) along a blend of each vertex normal and the direction from the mesh's middle, so a cube gets one closed line all the way round its silhouette. Being real thickness, it is the same weight on a small prop and on a whole house, and thins on screen with distance like any other edge.
**How the outline starts.** The engine compiles a shader on demand, when a material first waits on it, and nothing else in a world draws with the outline shader. So the package ships one small startup asset, `outline.toonStartup` (asset type `toonStartup`). The engine runs that type's load hook on every machine that loads the world: at world load, on install, and when the asset arrives from another player. The hook loads `ToonInk` and calls `ToonInk.start()`, which:
- opens the shared outline switch channel and asks the room for the switches already made, so a player who joins later, or whose machine opens the channel late, gets every outline already switched on;
- starts the `toonInk` render feature. From its first frame the feature makes its outline material on the shader's current key. That wait is what makes the engine compile the outline shader, which takes a fraction of a second, so the shader is ready before the first outline is switched on. Once a second the feature checks that its material is still on the program the engine holds for the shader, and remakes it when the shader has changed.
`ToonInk.start()` is safe to call again, and runs by itself whenever `ToonInk` is required.
**One place for the whole set's look** is `ToonLook`:
```luau
local ToonLook = require("~toonMaterials.ToonLook")
ToonLook.set({ bands = 4 }) -- four light bands on every cel, flat and hand-painted material, for every player
ToonLook.set({ outlines = false }) -- every ink outline off, for every player
ToonLook.reset() -- back to the defaults
print(ToonLook.get().bands)
```
`set` also takes `shadowLift` (how much light the darkest band keeps, default 0.45) and `rim` (the thin pale rim, default 0.18).
**The ink weight is fixed.** Every outline is drawn 3 cm thick, the same on every object for every player. `ToonLook` also stores and shares an `inkWidth` setting, but changing it does not change the line you see: a live change to the outline material's weight does not reach the drawn line (engine issue #21428). So `ToonLook.set` changes the bands, the shadow, the rim and whether outlines are on, and the outline keeps its 3 cm weight. Changes are shared through the library's `Sync`, newest write wins, and a player who joins later gets the current look. To change the defaults themselves, edit `ToonLook.DEFAULTS` and the palette (`ToonLook.PALETTE_HEX`, sRGB) and run `require("~toonMaterials.ToonCatalog").build()` (after `require("~toonMaterials.ToonRecipes").bakeAll()` when the palette changed), which writes them into every material file.
## The gallery and the toon corner
This world opens in the library's swatch gallery on the ring holding every toon material: each bay shows its material on a cube, a sphere, a shader ball and a cylinder (the cube and sphere outlined, the shader ball and cylinder plain, so each bay shows the material with the outline on and off), a floor tile and wall at real size, its reference picture beside it, and a label on one shared grid that reads from the spawn (name, kind, family and tile, textures and memory, whether it glows or moves). The toolbar switches the six lighting looks for everyone. Ahead and to the left of the spawn, in an 11 m opening of the ring (so it hides none of the labels from any spawn spot), stands a little toon corner made only from these materials: a brick cottage with a hand-painted tiled roof, a plank door and a glowing window, a stone path, a tree, grass, dirt, sand, rocks and a pond, outlines on.
In a scene of your own, in its `content()`:
```luau
local ToonGallery = require("~toonMaterials.ToonGallery")
local ToonCorner = require("~toonMaterials.ToonCorner")
entity.spawn("Gallery").component.add("ToonShowcase", { driveGallery = true, lighting = "daylight", ringGap = 11 })
local spot, facing = ToonGallery.gapSpot(11, 1.2) -- the opening ringGap leaves in the ring
ToonCorner.build({ position = spot, facing = facing }) -- the corner stands in it, facing the middle
```
## How they were made
- **Reference pictures first.** Every material has `references/<id>`, a picture generated before the material was drawn (a sample of the surface and a cube and sphere wearing it). Each material was compared with its picture side by side in the Daylight and the dark Moonlight looks and changed where they differed (the rock re-cut into big cliff facets, the painted grass and leaves redrawn, the water's ripples and the glow's core redone). A second pass in 1.0.1 closed what still differed: the brass now runs from deep bronze to bright gold with a white glint through a sky and ground reflection split, the painted stone wall's stones are the picture's mid blue-grey in charcoal joints, the darkest band is darker so the three bands read on every sphere, and the ink is one bold line all the way round as in the pictures.
- **Baked procedurally in Luau** by `ToonBaker` (forked from fantasyMaterials' FantasyBaker, MIT) and `ToonRecipes`, from the shared palette, at real size. Every map is periodic over one repeat, so it tiles by construction. `ToonEntries` is the single definition of every material; `ToonCatalog.build()` writes the materials and the collection.
- **One shader**, `toonSurface`, for all 24 (cel, painted and gradient modes; based on organicMaterials' `toonOrganic`, MIT), and `toonInk` for the outline (after the engine's `outline_hull`).
- **Searched and reused:** the library core and its checks, gallery, picker and lighting looks; the engine's `cel_shaded` material and `extended_material` shader (bands only, no shared tint or rim, so not used directly) and `outline_hull`; the toon shaders of the organic, sci-fi, woods, stone, metals and fabrics collections. The engine's screen-space outline was not used because it draws through walls in front of an object. Nothing from the other collections is a dependency.
## Tests
```luau
asset.resolve("toonMaterials.tests.toonMaterials", "testSuite"):run()
```
Seven quick tests on the library core's checks: all 24 registered and tagged, each reads as what it is (palette hues, flat colours, a legible render per family), seams on three tiled materials, the texture budget, the shared look changing all 24 at once, the outline switches, and the outline being ready with no setup (the startup asset ran, the feature is live, its material is on a compiled program within a few seconds, and a switch arriving from another player outlines the object here and takes it off again). Each runs inside the library's `Sync.isolate()`, so nothing reaches other players, and the gallery stands as it was afterwards: when a suite ends, the engine's test runner hands the world back and then lets go of what the run drew, which can blank the plaques' text, so `ToonShowcase` makes its own labels again 10 s after any gallery build. On 2026-11-01, on engine library d574006 (the one the engine runs), the suite passed 7 of 7 twice in a row in this world, and the gallery's plaques read normally afterwards; earlier that day, on engine library e70ec37, 1.0.5 passed twice in a row here and in a new world holding only the published package. The engine's runner logs about 150 to 220 "entity(...) returned nil" lines per run from its own sweep for leftover entities; they come from the runner, not from this package, and fail nothing.
## Fresh install
Installing toonMaterials puts two packages in your world. toonMaterials itself lands at `/source/toonMaterials.package`. The material library it needs, materialLibraryKit 1.4.2, comes along with it and lands in a folder of its own, `/source/deps/<world>/materialLibraryKit.package`, where `<world>` is the id of the world the library is published from (`a8c1db81-44f9-4da4-a9a5-4dc8095cdd7f`). The `deps/` folder is where an install keeps the packages it brought along for another one: leave it in place, toonMaterials needs it. Nothing else comes with it, no copies of the engine's shaders or other engine parts, because the package is published from a world on the engine library the engine runs. If you later install materialLibraryKit on its own as well, the library moves to `/source/materialLibraryKit.package`, the `deps/` folder goes away and the world still holds one library. **Then reload the world.** Until you do, the library reports problems for some of its own calibration materials (such as "material .../materialLibraryKit.package/materials/albedoRange.material does not resolve") and lists fewer than its 20, and these problems do not go away by waiting. Reloading the world clears them, and also makes outline switches from other players arrive again (#22328, see "Known limits"). Running `require("~materialLibraryKit.Materials").refresh()` also clears the library's problems.
Checked on 2026-11-01 by installing 1.0.7 from ZeroMind into a new, empty world (1.0.8 to 1.0.10 change only the texts): the install brought exactly those two packages, `Materials.collections()` listed `calibration 1.4.2 20` and `toon 1.0.7 24` with no problems, and the first example above ran as written: the cube wore `toonMetal` and its ink outline, `Materials.apply(cube, "toonBrick")` swapped it, and `ToonInk.set(cube, false)` and `true` took the outline off and put it back. Installing materialLibraryKit on top was checked again on 2026-11-01 in two more new worlds, each with 0 problems, 20 calibration and 24 toon materials before it. It left one library at `/source/materialLibraryKit.package` and no `deps/` folder, but right after it the library reported problems for its own calibration materials, starting with `albedoRange` (3 in one world, with 17 of the 20 calibration materials listed; 10 in the other, with 10 listed). In the first world they were still there after 4 minutes; `Materials.refresh()` then brought it back to 0 problems and 20 calibration materials. In the second world, leaving it and opening it again (a reload) brought it back to 0 problems and 20 calibration materials. The example guide was followed step by step in another new world (see its own page for what it builds).
## Multiplayer
Applied materials (`Materials.apply`), outline switches (`ToonInk.set`), the shared look (`ToonLook.set`) and the lighting look go through the library's `Sync`, so every player sees the same, and a player who joins later is sent the current state. The outline is drawn by each player's own machine; the startup asset makes sure every machine listens for the switches and draws them, in any world that installed the package (after installing materialLibraryKit on top of toonMaterials, reload the world once first: #22328 in "Known limits"). The water and the glow animate from the shader's own clock on each machine, so they cost no traffic. The gallery and its boards are local and rebuilt the same on every machine. Another player is stood in for in the tests (a switch arriving through `Sync` from outside), since two engines signed in to one account join a room as one player (#14448).
## Gallery frame rate
- **Web (browser): 38 fps median (p50)**, 36 to 41 fps over two runs, measured by the world's owner in Chrome on a busy desktop with the whole 24-bay gallery and the toon corner standing. The gallery's own upkeep is what costs the frame in the browser (#20750); materials on ordinary scene objects in your own world do not carry it.
- **Desktop engine:** 60 to 85 fps (12 to 17 ms a frame) for the same scene.
## Known limits
Engine issues are listed by their number at github.com/OrigoZero/zero.
- **Gallery frame rate on the web (#20750).** The gallery is about 270 local entities, and the engine's per-frame upkeep of them dominates the frame in the browser: 38 fps median (36 to 41) measured in Chrome. In your own world, with the materials on ordinary scene objects, that does not apply.
- **No browser check by the author (#20946).** An agent on the desktop engine cannot start a web engine, so this release was prepared and checked on the desktop engine; the web frame rate above is the owner's measurement.
- **Long waits (#19849).** A full re-bake (`ToonRecipes.bakeAll()`) takes about 90 s and a check sweep many seconds; some calls answer late.
- **Reload the world after installing the material library on top (#22328).** When materialLibraryKit is installed on its own after toonMaterials is already in the world (the library moves from `deps/` to `/source/materialLibraryKit.package`), an outline switch sent by another player is not picked up on that machine until the world is reloaded: the object stays as it was on your screen while it changes on theirs. Reload the world once after installing the library on top; from then on outline switches arrive as usual. Until the reload, the library also reports problems for some of its own calibration materials and lists fewer than 20 of them; they do not clear by waiting, and the reload (or `Materials.refresh()`) clears them (see "Fresh install"). The same install also logs a "package collision" error (#20868). It is harmless: one library is left and it works.
- **Slow installs with several dependencies (#21420).** Installing several material collections in one call can run past a call's time limit with only some of them landed; install them one at a time.
- **Guides are not found by ZeroMind search yet (ZeroMind#3099, engine #22181).** The two guides ship inside the package and open in the engine once it is installed; a ZeroMind search does not reach them.
- **Open a guide by its full path (#22286).** `toonMaterials.package/guides/makeYourGameLookLikeACartoon` opens; the short guide name alone does not.
- **The ZeroMind description can lag a release (#19258).** After a release the description on ZeroMind can still show the previous README for a while; this README in the package is the current one.
- **Reloading the scene can save runtime things (#21023).** The gallery's swatches are temporary and rebuilt each time; check the scene file before committing after a reload.
- **Flat labels read from the front only (#21224).** The gallery's plaques face the middle of the ring; from behind a bay they read mirrored.
- **Self-lit surfaces in the debug views (#21225).** `toonSurface` does its own lighting, so the capture tool's albedo, roughness and metallic passes draw these materials magenta; the library's seam check falls back to the final render for them. Their final and normal views are right.
- **Gallery labels (#22336).** A test run can leave the gallery's plaques drawing blank text: the test runner lets go of what the run drew a few seconds after it ends. `ToonShowcase` makes its own labels again 10 s after any gallery build, which brings them back. A Text3D label whose text and size are rewritten after it first drew can also keep its first text on screen beside the new one, so `ToonShowcase` never rewrites the library's labels: it parks them out of sight and draws its own, each made once with its final text.
- **A push can report a timeout and still land (#21025).** Check the world's commits before pushing again.
- **The ink weight does not change live (#21428).** Setting `ToonLook.set({ inkWidth = ... })` is stored and shared, but the outline keeps drawing at 3 cm: a property change on the outline material does not reach the drawn line. The weight is the same 3 cm on every object and every player.
- **The outline is a hull.** It outlines silhouettes, not creases inside a shape, and a flat single-sided surface (a floor tile seen from above) has no outline. Its weight is real thickness (centimetres), so it thins on screen with distance.
- **No outline on skinned characters.** The outline is drawn for parts with a `Model`. An animated, skinned character (such as the engine's Fox) takes a toon material but no ink outline; characters built from plain model parts (such as the engine's alien) take both.
- **The outline shader compiles on demand.** The engine compiles a shader only when a material waits on it. Up to 1.0.1 nothing did that for the outline shader on a fresh start, so outlines stayed invisible until something prepared it by hand, and other players never saw them. Since 1.0.2 the outline feature makes its material on the shader's key from its first frame, on every machine, which is what asks for the compile. A material also keeps the program it was made with, and a render feature can draw nothing after an engine restart (#21424), so the feature checks once a second and remakes its material on the program the engine holds.
- **Keep `outline.toonStartup` in the package.** It is what starts the outline on every machine. Without it, only machines whose own code requires `ToonInk` hear the switches and draw outlines.
- **World mapping is per face direction.** `ToonProp`'s `worldScale` projects along the main axis of each face, so on a sphere the pattern meets itself at the diagonals.
## Version history
- **1.0.10 (2026-11-01):** the package description says how to install the package and how to use it first. Nothing else changed.
- **1.0.9 (2026-11-01):** README fix. "Fresh install" said that after installing materialLibraryKit on top the library's problems clear by themselves after a few seconds. They do not: they stay until the world is reloaded (or `Materials.refresh()` runs), and the README now says that is the step to take, in "Fresh install", "Use it together with the material library" and the #22328 known limit. Everything else is unchanged.
- **1.0.8 (2026-11-01):** text fixes only. "Fresh install" now says what an install really puts in a world: toonMaterials, and the material library in a folder of its own under `/source/deps/` (it said, wrongly, that no `deps/` folder was made). "Use it together with the material library", the multiplayer section, the how-to guide and the package description point to a new known limit: after installing materialLibraryKit on top of toonMaterials, reload the world once (#22328). The gallery labels limit cites the open issue #22336. Materials, shaders, code, tests and the material library are unchanged, so the toon collection and the material files still say 1.0.7.
- **1.0.7 (2026-11-01):** no copies of engine parts. 1.0.6 was published from a world on an older engine library (e70ec37) than the engine now runs, so installing it put five copies of engine parts (the lit and unlit shaders, the shadow pieces and the engine bindings) in a `deps/` folder. This world is now on the engine library the engine runs (d574006) and 1.0.7 is published from it: a fresh install brings toonMaterials and the material library and nothing else. The version every place shows is 1.0.7. Materials, colours, outline, guides, the material library (1.4.2) and texture memory are unchanged.
- **1.0.6 (2026-11-01):** moved onto the current material library, materialLibraryKit 1.4.2 (was 1.3.1). Before, installing toonMaterials and then the current library left two packages named `materialLibraryKit` in the world and the library could not be used at all; now either order leaves one library, the current one. New README section "Use it together with the material library". The version every place shows is the release: the toon collection, `Materials.collections()` and the material files said 1.0.3 and now say 1.0.6. The 7 tests pass on the new library. Materials, colours, outline, guides and texture memory are unchanged.
- **1.0.5 (2026-11-01):** two guides ship in the package: "How to make my game look like a cartoon" and "Make a cartoon game scene from an empty world" (a cel-shaded village with characters, props and ground). Rechecked on today's engine library (e70ec37): the first example and all 7 tests pass, twice in a row, here and in a new world. The gallery's plaques no longer stay blank after a test run (today's test runner lets go of what a run drew after it ends; `ToonShowcase` now makes its labels again 10 s after any gallery build). Text fixes: `ToonProp` (not a `ToonOutline` that never existed) outlines a scene object from the scene file; the known limits name skinned characters, which take no outline. Materials, colours, outline, the bands and texture memory are unchanged.
- **1.0.4 (2026-10-31):** `toonSurface` takes vertex colours when asked: a new `vertex_tint` property (0 by default, so every existing material looks exactly as before) multiplies the mesh's vertex colours into the colour at 1. One cel material can then paint a whole mesh whose vertices carry their own colours, such as procedurally built plants (cropsKit's cosy look uses it). Nothing else changed.
- **1.0.3 (2026-10-27):** a clean start. `ToonInk` started the outline renderer while it was still loading, and the renderer's code requires `ToonInk`, so every fresh start logged two "cyclic require detected" errors and a warning that the renderer could not start, until a later switch started it. `ToonInk` now opens its switch channel at load and starts the renderer one frame later. The README and the world description no longer promise a live change of the ink weight: it stays at 3 cm (engine issue #21428, now in the known limits). Materials, colours, outline switching, the bands and texture memory are unchanged.
- **1.0.2 (2026-10-27):** the outline shows by itself, for everyone. On a fresh start the outline shader was never compiled, because the engine compiles on demand and the outline feature only made its material once a compiled program existed, so it waited forever. Other players' machines also never loaded the outline module, so they never drew the rim. Now the new `outline.toonStartup` asset (type `toonStartup`) starts `ToonInk` on every machine at world load. Its channel asks the room for the switches already made, and the outline feature makes its material on the shader's key from its first frame, which has the shader compiled within a fraction of a second. A seventh test checks both. Materials, colours, outline switching, the shared look and texture memory are unchanged.
- **1.0.1 (2026-10-27):** the review fixes. The ink outline is one closed line all the way round every shape, pushed out by 3 cm of real thickness in the shader's object-space hook. In 1.0.0 it was written in the clip-space hook, which the render feature's geometry pass never runs, so only the hull's back faces peeked out on one edge; and after an engine restart the outline material could wait forever for its shader, which left the outlines invisible. The feature now binds its material to the shader's current program, and the gallery and `ToonProp` put their ink back by themselves if a reload drops it. The gallery's labels are the showcase's own, made once with their final text, so no plaque shows the library's text underneath. The darkest light band keeps less light (0.45, was 0.6) under a calmer cool tint, so the bands read on every sphere. Two-tone brass runs from deep bronze to bright gold with a white glint; the hand-painted stone wall is mid blue-grey as in its picture. The corner's tree crown is all foliage (the plain green blob is gone). The corner stands in an opening of the gallery ring (`ToonShowcase`'s new `ringGap`, `ToonGallery.gapSpot`), so every label reads from every spawn spot. `ToonProp` puts an object's ink back by itself if a module reload drops it. Same 24 materials, names, tags and texture memory.
- **1.0.0 (2026-10-27):** first release: the 24 materials, their reference pictures, `toonSurface` and `toonInk`, `ToonLook`, `ToonInk`, `ToonProp`, `ToonShowcase`, `ToonCorner` and the six tests.
▲ 0↑ born
backing path · toonMaterials.package/materials/rampFoliage.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.