A material describes a surface: its color, how glossy it is, whether light passes through it, what light it gives off itself. Every drawn part names one shape and one material; the shape says where the surface is, the material how it answers light. A material is a value of type material with an identity: several parts may refer to one material, as several references point at one struct, and then one change to it (the dusk glow) reaches every part drawn in it. This page covers the material type and its fields, how parts refer to materials, the kinds of material the browser offers, the per-part tint, and the renderer settings that sit on materials and parts. Images painted onto materials are on Textures and surface patterns.
Words used on this page:
- Emission
- Light a surface gives off itself, whatever lights it, in nits (candela per square meter: a screen's or a lamp's surface brightness). Written
glow. - Roughness
- 0 a mirror, 1 fully matte, in a physically based material.
- Metalness
- 0 not metal, 1 metal: a metal's reflection takes its color, a non-metal's does not.
- Tone mapping
- The last step of drawing a picture, squeezing brightnesses from moonlight to sunlight into what a screen shows. A common choice is AgX, which pales very bright colors toward white.
- Bloom
- A soft halo spread round very bright points of the picture, which makes emission read as glowing.
How you write it
A material, held by a part
A material is declared under whatever part holds it, as a part holding the material, part name: constructor(...), and may have fields. The world's root holding a frameless part named materials is a convention of arrangement, not meaning: a material may equally be held by the cottage design or by one lantern. It lasts as long as its holder, and anyone refers to it by path.
part materials // a part with no frame: a holder
part lanternBlack: shiny(srgb(12, 13, 17), highlight: 0.9, shininess: 90) // the stakes
part lanternMetal: shiny(srgb(88, 62, 40), highlight: 0.22, shininess: 12) // a bracket
part lanternHead : [shiny(srgb(88, 62, 40), highlight: 0.22, shininess: 12),
litByLayers([world, interior]), // frame, roof, plinth
glowing(color: glassColor, strength: glow)]
field glow: nits = 0 nits // derived (below): not mutable
part lanternGlass: [shiny(srgb(255, 205, 130), highlight: 0.45, shininess: 30),
translucent(covers: 0.12), // the panes and lining
glowing(color: glassColor, strength: glow)]
field glow: nits = 0 nits // derived (below): not mutable
part lanternBulb : [plain(srgb(255, 214, 122)), // the filament
glowing(color: lampColor, strength: glow)]
field glow: nits = 0 nits // derived (below): not mutable
part room : [shaded(rooms, color: srgb(150, 120, 92), ambient: 0.25), // the rooms behind the windows
glowing(color: roomColor, strength: glow)]
field glow: nits = 0 nits // derived (below): not mutable
part windowGlass : clearGlass(bends: 1.5, thickness: 6 mm,
inside: leavesAfter(10 cm, (0.86, 0.93, 0.88)))
part cottageBoards: [physical(color: white, roughness: 1),
paintedBy(surfacepatterns.PlankParams.siding(512, seed: 1928))]
A surface's color is written srgb(r, g, b), 0 to 255 (the screen's familiar numbers), turned into linear values for lighting; a glow's color is linear, color(r, g, b) (Values: colors).
How the lines are laid out. A material is a constructor, or a list of a base material (a constructor) and its modifiers, in brackets and separated by commas; a line ending in a comma goes on, and its continuation lines are indented further than the part word, aligned under the first item by custom. What the part holds (its field glow, any children) comes after the whole line, indented one step under the part word (Parts). The room material is one of the browser's own shaders, rooms: a warm beige room by day lit by a quarter of the ambient light, and at night the glow its glow field gives.
The rooms material goes on a part whose shape fills the window opening. The shader draws the room as seen through that shape, so the shape is a flat rectangle, a little behind the glass, with its texture coordinates running 0 to 1 across the window (the island puts each one 9 mm behind its pane). A room behind a window 0.82 m wide and 1.31 m tall:
fn windowRoom(w: meters, h: meters) shape {
uvAt(face([(0, 0, 0), (w, 0, 0), (w, h, 0), (0, h, 0)]), p => (p.x / w, p.y / h))
}
part gableRoom: windowRoom(0.82 m, 1.31 m), material: materials.room, at: (-0.42 m, 3.8 m, -9 mm)
A glow: its color and its strength
glowing(color: c, strength: s) is a material modifier: the surface gives off light of color c at brightness s, in nits, whatever lights it. The glow is c with each of its channels multiplied by s: a color of (1, 0.3, 0.045) at a strength of 2800 gives off (2800, 840, 126) nits. strength may be a number of nits, or the name of a field of the material's own part, as glow is above: the glow then follows that field, and a derive on the field moves every surface drawn in the material. The color says which light; the field says how much. The lantern's three glowing materials share one pattern with different colors: the bulb glows in the lamp's own color, lampColor (linear (1, 0.397, 0.0953), about 2700 K), and the glass and the bronze head in a deeper amber, glassColor (1, 0.3, 0.045), so the tone map leaves the panes amber rather than peach. Both colors are fixed fields of the world, named once (The lanterns).
A part drawn in a material
part lanternHead part glass: panes(size), material: materials.lanternGlass part bulb : filament(size), material: materials.lanternBulb
material: names a material by path (Parts: options). Inside a design a part's other names are relative (glass, self.parent.lantern[13]); a material held at the world's root is named from the root, so the same line works in every copy wherever it is placed. A part refers; it never describes a look of its own and names a shared one at once.
One value reaching every user
derive(materials.lanternBulb.glow, lampLevel * bulbBrightness.at(eveningHour(hour(now(world))))) derive(materials.lanternGlass.glow, materials.lanternBulb.glow * 0.09) derive(materials.lanternHead.glow, materials.lanternBulb.glow * 0.0015) derive(materials.room.glow, materials.lanternBulb.glow * 0.4)
The bulb material's glow is the world's lamp level times the brightness for the hour: about 2800 nits at dusk (17:28), falling to 1.3 nits from 20:00, because the picture's exposure rises about 5000-fold over the evening. The brightness is world data, a curve held in the world's field bulbBrightness: eight evening hours and the bulb's radiance at each, blended on a log scale, a morning hour read as the evening hour mirrored about noon by the world's function eveningHour (both written out on Lights: the world's lamp level). The glass glows at 0.09 of it, the bronze head at 0.0015, a faint warm lift, not a light, and a lit room behind a window at 0.4. Since every bulb is drawn in this one material, one formula lights fourteen lanterns.
Delivery is the engine's business. Content states what the glow is at every moment. When a changed value is sent to the renderer (only once it has moved by more than a hundredth, say), and any counts kept of what was sent, belong to the engine: content neither states nor reads them. A test that wants to see them uses the browser's test tooling (Outside the content: test hooks).
One part different: the tint
part pathLantern: lanternHead field gain: number = 1, within: 1 ..= nearGain, mutable: true // brighter while someone is near derive(glass.tint, gain) // this lantern's parts only: a number, a gray derive(bulb.tint, gain)
Every drawn part has a field tint, a color whose default is white, which a derive or a set may write. A tint multiplies one part's color and glow, and the colors of a painted material too (the image's texels times the tint); white means "as the material is". The conifers' age tint is the part's tint, a color whose components pass 1 (it runs from about (2.7, 3.0, 1.0) for a young tree to (0.78, 0.86, 0.92) for an old one), and a tree's foliage takes its part's tint. It may be written as a color, or as a number n, meaning the gray (n, n, n): a gain of 1.45 makes the glass and bulb 1.45 times as bright in every color, with their hue unchanged. The material is untouched and the other thirteen lanterns stay as they are. It is the one per-part change to a shared material: the material says what the surface is, the part may only scale it.
What it means
The material type
"Shared" is not a kind. The type is material; sharing is only several parts referring to one instance. An instance has identity and may have changing fields (the bulb's glow); it lives wherever it is held (the world's root, the cottage design, one lantern) and lasts as long as its holder. Sharing across kinds is common: lantern and wall lantern; rocks and edging stones; oak for doors, beams and hulls; one wetness darkening every surface in rain.
Sharing is meaning or mechanism
A shared material is sharing a change can observe: if a change to it would reach several users, it is meaning, and the renderer may never split it. Sharing that nothing can observe (twelve lanterns drawn as copies of one mesh, which nothing changes) is a resource choice, the browser's. The two forms of a glow differ in meaning, not only in cost:
| A glow on the shared material | A glow field on each lantern | |
|---|---|---|
| How many values | one | fourteen |
| What a change reaches | every part drawn in the material; nothing can light one alone | one lantern; lighting all is fourteen changes, or a rule on the design run per copy |
| What can differ | only a tint | anything |
| What must be kept in step | one value, or none if every browser works it out from the clock | fourteen |
The lanterns mean both at once: one shared glow for the schedule, and a per-lantern multiplier (the tint) for nearness. The content says which it means.
Order does not change meaning
A material is defined once, in its own place. Two definitions under one path are refused when the world is loaded. A part whose material has not yet arrived waits for it, or is drawn with a stand-in and corrected; it never defines it. Removing an object never removes a material its parts used, unless the object holds it.
Where a material's fields live
A material's field lives where the rules that read and write it run. The glow is a formula of the clock and the lamp level, so every browser could work it out for itself. Network cost never appears in content.
The kinds of material
The browser offers one material record, filled by constructors and changed by modifiers:
| Constructor | What it describes |
|---|---|
plain(color) | a color, no highlight: a matte surface |
shiny(color, highlight: fraction, shininess: number) | a color plus a highlight of a strength (0 to 1) and tightness: the older Blinn-Phong model |
physical(color: color, roughness: fraction | image = 1, metal: fraction = 0) | the physically based model, which never reflects more light than it receives. The defaults are a fully matte non-metal. roughness may be a number or a one-channel image made by painted(valueAt: ...) (Textures: painting an image) |
clearGlass(bends: number, thickness: meters, inside: leavesAfter(distance, color)) | glass that bends light (bends is its index of refraction), dimmed by its color inside; ray-traced where the graphics card can, else drawn by bending the picture already drawn |
shaded(shader, ...) | one of the browser's own shaders by name, with its own named values: terrain, water, brook, rooms (the rooms behind the windows: color:, ambient:), the view surface |
A bare color is not a material. Wherever a material goes (material:, the list that makes one), write one: the plainest material of a color c is physical(color: c), fully matte and not metal.
Modifiers, each changing one setting, follow the constructor as the later items of a list, [constructor, modifier, ...]: matte, specular(amount: number) (the specular highlight as a share of the usual: matte is specular(amount: 0), and the island's conifer needles are specular(amount: 0.12)), backlit(share: number) (lit from behind when the sun is behind it: the maple leaves; a bird's wing is backlit(share: 0.25), the side away from the sun taking a quarter of the diffuse light the side facing it takes; the share is a factor that may exceed 1, since a thin leaf passes more than it receives in its own color: the maple's is backlit(share: 1.2) and the conifers' 0.9; written bare, backlit takes the browser's usual share), fluttering(amount: angle) (the most a leaf turns about its stem, each on its own period of 0.6 s to 1.8 s: the maples' fluttering(amount: 0.12 rad), about 7 degrees; it needs the foliage to carry its leaves' pivots, sway: true, Generators), translucent(covers: fraction) (see-through by blending: covers is how much of what lies behind it is hidden), dispersing, frosted, litByLayers (which lights reach it), cutOut(threshold: fraction) (holes where an image's alpha is below the threshold: the needle cards, cutOut(threshold: 0.5)), glowing(color:, strength:) (above), and paintedBy(image), which works on every kind (Textures). The ConeScript names on this page are provisional spellings; the vocabulary names for materials are not yet chosen, but each is spelled one way everywhere in this manual.
Two-sided. A shape's faces are one-sided: a face is seen only from the side it faces (Shape tools: primitives). A thin sheet seen from either side, such as a wing or a leaf, is drawn with the material option twoSided: true, a named option of the material's part, not an item of its list: part birdWing: [physical(color: color(0.075, 0.062, 0.05), roughness: 1), backlit(share: 0.25)], twoSided: true. The side turned away from the eye is shaded as if it faced it.
Underneath, the render package's material record (PbrMaterial) is far richer: base color, metallic, roughness, clearcoat, a thin iridescent film, wetness, textures for color, metal-roughness, normals and occlusion, emission, alpha mode and cut-off, transmission, flutter, specular scale, light layers, sheen, anisotropy, subsurface scattering, glass with index, thickness, absorption and dispersion, and builders for standard, chitin, glowing, translucent, cut-out, coated, iridescent, wet, soaked, velvet, brushed, skin, wax, glass, frosted, reflective and caustic-receiving surfaces. A world's vocabulary of materials would be drawn from this, not from Look.
The pbrmaterial package says what goes into a physically based material, as opposed to how it is lit: its per-texel output is a base color, roughness, metallic, occlusion, wear and grime, baked into a texture set (bakeTextureSet). It has no layered materials and no material graph; parameter fields evaluated in shaders (a film's thickness, a wet mask) and GPU bakes are not built.
Two models of gloss
"Shiny" and "physical" describe the same thing, a surface's gloss, in two models, and a world's numbers mean different things in each: in shiny(..., highlight: 0.22, ...) 0.22 is the strength of a Blinn-Phong highlight, not a roughness. A world written against one renderer's model fixes that renderer. Which model the vocabulary offers is open.
Light color and surface color
A light's color is the mix of wavelengths it gives off; a surface's color is its reflectance, the share of each color it sends back. What is seen is the light's color times the surface's: a shirt shows green only under light that contains green. An example lamp has four warm colors tuned by eye against its picture: the lamp's own, about 2700 K, linear (1, 0.397, 0.095), for the bulb's glow and interior light; a deeper amber (1, 0.3, 0.045) for the glass "so that the tone mapping leaves the interior amber and not peach"; the light thrown on the ground deeper still (1, 0.14, 0.01), because grass reflects mostly green; and a room's (1, 0.25, 0.028). The content there compensates for the grass and the tone map. Whether content states physical quantities (2700 K, a reflectance) or colors as they should look is open.
Renderer concerns on materials and parts
Several settings on materials and parts exist for the renderer, not for what the thing is:
- Light layers.
worldis the built-in layer: every material and every light is on it unless it says otherwise.litByLayers([...])puts a material on the layers it lists instead, so a material lit by both names both,litByLayers([world, interior]). Any other layer name (interior) is a layer of this world, with no declaration needed (Lights: light layers). Each lantern has a second, small light on theinteriorlayer, which only the head's material answers to, so the frame reads as lit from inside without the light brightening the grass a meter away; the ground, the stakes and the bracket name no layers, so they are onworldalone. The bracket and the head are two materials of the same color for this reason alone. - See-through.
translucent(covers: 0.12)sets alpha 0.12 and blending; the renderer must then draw every see-through thing after every opaque one, sorted back to front by object, testing depth without recording it. Light does not bend through it, and it casts no shadow by the renderer's own rule. - Clear glass requires a closed volume, a shape a ray can enter and leave: each window pane is a 6 mm slab. A flat pane would draw wrongly, with no error. A material can place requirements on a shape.
- Casts no shadow is set on a part, not on its material, with the part option
castsShadow: false:part bulb: filament(size), material: materials.lanternBulb, castsShadow: false. Every drawn part casts a shadow unless it says so. The bulb casts none (it is the light), nor do the lantern's plinth and tracery, made a part of their own because a point light's shadow of thin bars on the ground was a hard sunburst. Whether a light casts shadows is the light's own argument,castsShadow: true(Lights: shadows). - One material a part. A thing drawn in two materials is two parts (a draw request names one mesh and one material), so the tree divides by draw call: the labyrinth is one part for each of its 19 materials.
Whether these may appear in content at all, as declarations, or must be stated as requirements ("the light inside reaches the ground"; "the frame is lit from within") that the browser meets as it can, is open.
How it connects
- Textures and surface patterns: images painted by recipe, mapping.
- Lights: light layers, the lamp level, light color.
- Subscriptions:
deriveon a material's field. - Parts: holding, lifetime by holder, paths.
- Construction: the shape a material is drawn on; one description, several products.
- Cameras and views: the view-surface look of mirrors and portals.
Open questions
- May a renderer concern appear in content? Shadow casting, light layers, shadow-only parts: as declarations; never, only requirements; or some derived (a see-through part casts no shadow) and the rest requirements. A proposal now writes layers and shadow switches as declarations (light layers, casts no shadow); shadow-only parts, and requirements in their place, remain open.
- Physical or perceived color? Physical quantities and the engine answers for tone mapping; the color as it should look; or both, chosen per value.
- Emission on the material or the part?
- One glass or two? The lanterns' see-through amber and the windows' refracting glass: two names, or one glass with qualities, the browser choosing the method and checking the shape.
- One material a part, or several over regions of a shape, split by the browser for drawing?
- Which model of gloss: only physically based, translating the rest, or several?
- Override beyond tint: may a part override a material's roughness or paint, and how does that differ from a material of its own?
- Local or world-wide: may a subtree (the labyrinth) hold materials only its parts name? (By "lifetime by holder", yes; how names resolve is open.)
- Who may write a formula for a material that reaches several objects, and where in the content it belongs.
- Changing a definition while running: the glow is a field; replacing the leaf paint for autumn changes the definition itself.
- Arrival order: whether definitions always travel first, or what a part looks like while it waits.
- A look from where you are: a color chosen from the facing, the height or the side seen, not from texture coordinates: a wing darker above and paler below, a body shading from belly to back by the way its surface faces, a ground chosen from its slope and the distance to the eye. A bird stands in four parts (body, beak, tail, wings) for one mesh. A design question (Terrain).