StoneBaker
The procedural texture baker stoneMaterials is made with, built on Heartwood's periodic baker (MIT). Every field covers one texture repeat and every generator is periodic over it, so the textures tile with no seam by construction, and distances are in metres. Periodic value noise…
StoneBaker
The procedural texture baker stoneMaterials is made with, built on Heartwood's periodic baker (MIT). Every field covers one texture repeat and every generator is periodic over it, so the textures tile with no seam by construction, and distances are in metres. Periodic value noise, fbm, ridged noise, Worley cells, Poisson point sets, power-Voronoi cells with the true distance to the cell border, coursed block layouts, wrapped blur and domain warp, and the packers that write an sRGB albedo, a green-up normal map (raised = outward, so joints read sunk) and an AO/roughness/metal mask. Tool code: the recipe modules call it; never require it from a component.
Interface
What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.
conforms to
zero/source-extract/v2StoneBaker: the procedural texture baker stoneMaterials is made with. Tool code: run it from a tool, a test or an execute call, never from a component (baking one stone takes seconds). Built on the periodic baker of woodsMaterials (Heartwood, MIT): every field is a square n x n grid covering ONE texture repeat, and every generator is periodic over it (integer lattice frequencies, wrapped cells, wrapped blurs and derivatives), so every texture tiles with no seam by construction. Distances are in metres: a recipe knows its tile size, so a 12 cm cobble or a 40 cm ashlar course is drawn at its real size. Stone additions: periodic Poisson point sets, power-Voronoi cells with the true distance to the cell edge (cobbles, pebbles, flagstones, facets), ridged and domain-warped noise (marble veins, cracks), and periodic course layouts (walls). Image axes: x (U) across, y (V, image up). Courses and strata run along x. Maps written per stone: <id>_albedo sRGB colour, no lighting or occlusion painted in <id>_normal tangent-space normal, green = image-up (OpenGL / glTF) <id>_rm linear mask: R = ambient occlusion, G = roughness, B = metallic (0)
breathe( ) → void
Yield a frame once a bake has held the engine for 50 ms, so a long bake never freezes the editor.
mul32(a: number, b: number) → number
| arg | type | description |
|---|---|---|
| a | number | |
| b | number |
rng(seed: number) → void
A deterministic random stream: rng() returns [0, 1).
| arg | type | description |
|---|---|---|
| seed | number |
hash(a: number, b: number?, c: number?) → number
A stable 0..1 hash of up to three integers (cell ids, blocks).
| arg | type | description |
|---|---|---|
| a | number | |
| b | number? | |
| c | number? |
field(n: number, v: number?) → Field
| arg | type | description |
|---|---|---|
| n | number | |
| v | number? |
value2(n: number, fx: number, fy: number, seed: number, out: Field?, amp: number?) → Field
One octave of periodic value noise, fx cells across and fy cells along (integers), added into out scaled by amp.
| arg | type | description |
|---|---|---|
| n | number | |
| fx | number | |
| fy | number | |
| seed | number | |
| out | Field? | |
| amp | number? |
fbm2(n: number, fx: number, fy: number, octaves: number, seed: number, gain: number?) → Field
Periodic fractal noise 0..1, octaves doubling from (fx, fy) cells; anisotropic when fx ~= fy.
| arg | type | description |
|---|---|---|
| n | number | |
| fx | number | |
| fy | number | |
| octaves | number | |
| seed | number | |
| gain | number? |
fbm(n: number, f: number, octaves: number, seed: number, gain: number?) → Field
| arg | type | description |
|---|---|---|
| n | number | |
| f | number | |
| octaves | number | |
| seed | number | |
| gain | number? |
ridged(n: number, fx: number, fy: number, octaves: number, seed: number, sharp: number?) → Field
Periodic ridged noise 0..1 (1 on the ridge lines): 1 - |2·fbm - 1|, sharpened by `sharp` (a power).
| arg | type | description |
|---|---|---|
| n | number | |
| fx | number | |
| fy | number | |
| octaves | number | |
| seed | number | |
| sharp | number? |
worley2(n: number, cx: number, cy: number, seed: number, jitter: number?) → void
Periodic Worley cells, cx across by cy along (anisotropic cells). Returns F1, F2 (in cell units) and a 0..1 id per nearest cell.
| arg | type | description |
|---|---|---|
| n | number | |
| cx | number | |
| cy | number | |
| seed | number | |
| jitter | number? |
poisson(tile: number, tileY: number, minDist: number, seed: number, maxPoints: number?, wRange: { number }?) → void
Periodic dart-throwing point set over a tile x tileY metre repeat: points at least `minDist` apart (wrapping), optional per-point radius range for power cells. Each point: { x, y (metres), w (weight radius, metres), id (0..1) }.
| arg | type | description |
|---|---|---|
| tile | number | |
| tileY | number | |
| minDist | number | |
| seed | number | |
| maxPoints | number? | |
| wRange | { number }? |
cells(n: number, tile: number, tileY: number, pts: { Point }, aspect: number?) → Cells
Periodic (power) Voronoi cells of a point set over a tile x tileY metre repeat, sampled on an n x n grid. Each point's `w` (metres) grows its cell (power distance d^2 - w^2), so stones of different sizes pack. `aspect` stretches distances along y (1 = isotropic). Returns the true distance to the cell border, the distance to the site, ids and site offsets.
| arg | type | description |
|---|---|---|
| n | number | |
| tile | number | |
| tileY | number | |
| pts | { Point } | |
| aspect | number? |
courses(tile: number, tileY: number, rows: number, lenRange: { number }, hJitter: number, seed: number) → void
A periodic coursed layout over a tile x tileY metre repeat: `rows` courses (heights jittered by `hJitter`, summing to tileY), each cut into blocks of length between lenRange[1] and lenRange[2] metres with the cut positions wrapping across x. Returns the blocks; use M.blockField to rasterise.
| arg | type | description |
|---|---|---|
| tile | number | |
| tileY | number | |
| rows | number | |
| lenRange | { number } | |
| hJitter | number | |
| seed | number |
blockField(n: number, tile: number, tileY: number, blocks: { Block }) → BlockMap
Rasterise a periodic block layout (M.courses) onto an n x n grid: distance to the block's own border, its id, and the pixel's position within it.
| arg | type | description |
|---|---|---|
| n | number | |
| tile | number | |
| tileY | number | |
| blocks | { Block } |
blur(n: number, src: Field, r: number, passes: number?) → Field
Periodic separable box blur of radius r texels (passes times, ~gaussian at 3).
| arg | type | description |
|---|---|---|
| n | number | |
| src | Field | |
| r | number | |
| passes | number? |
normalize(n: number, f: Field, p: number?, q: number?) → Field
Remap a field so its p-th and q-th percentiles land at 0 and 1 (clamped).
| arg | type | description |
|---|---|---|
| n | number | |
| f | Field | |
| p | number? | |
| q | number? |
sample(n: number, f: Field, x: number, y: number) → number
Bilinear sample of a periodic field at fractional texel coordinates (x across, y along), wrapping.
| arg | type | description |
|---|---|---|
| n | number | |
| f | Field | |
| x | number | |
| y | number |
warp(n: number, f: Field, wx: Field, wy: Field, amount: number) → Field
Domain warp: resample a periodic field with each pixel displaced by (wx, wy) fields (0..1, centred at 0.5) times `amount` texels.
| arg | type | description |
|---|---|---|
| n | number | |
| f | Field | |
| wx | Field | |
| wy | Field | |
| amount | number |
resize(n: number, f: Field, m: number) → Field
Resample a periodic field to size m (box-filtered down, bilinear up).
| arg | type | description |
|---|---|---|
| n | number | |
| f | Field | |
| m | number |
smoothstep(a: number, b: number, x: number) → number
| arg | type | description |
|---|---|---|
| a | number | |
| b | number | |
| x | number |
lerp(a: number, b: number, t: number) → number
| arg | type | description |
|---|---|---|
| a | number | |
| b | number | |
| t | number |
lin(s: number) → number
Linear value of an sRGB 0..255 colour channel, for writing palettes the way they are measured.
| arg | type | description |
|---|---|---|
| s | number |
rgb(r: number, g: number, b: number) → void
A linear RGB triple from an sRGB triple (0..255).
| arg | type | description |
|---|---|---|
| r | number | |
| g | number | |
| b | number |
mix(a: { number }, b: { number }, t: number) → void
Linear interpolation between two linear RGB triples.
| arg | type | description |
|---|---|---|
| a | { number } | |
| b | { number } | |
| t | number |
newMaps(n: number, tile: number) → Maps
A blank set of maps: mid-grey albedo, flat height, open AO, roughness 0.85.
| arg | type | description |
|---|---|---|
| n | number | |
| tile | number |
aoFromHeight(m: Maps, radius: number, depth: number, strength: number) → void
Fill a stone's AO from its height: cavities `depth` metres below the local average (blur `radius` texels) go dark by `strength`.
| arg | type | description |
|---|---|---|
| m | Maps | |
| radius | number | |
| depth | number | |
| strength | number |
percentile(f: Field, p: number) → number
The p-th percentile (0..1) of a field, from a sample of about 2048 values.
| arg | type | description |
|---|---|---|
| f | Field | |
| p | number |
paint(m: Maps, col: (number) → void
Set each pixel's albedo from a linear RGB palette lookup: col(i) returns {r,g,b} for pixel i.
| arg | type | description |
|---|---|---|
| m | Maps | |
| col | (number |
toSrgb8(c: number) → number
| arg | type | description |
|---|---|---|
| c | number |
packAlbedo(n: number, r: Field, g: Field, b: Field) → buffer
Pack an albedo from three linear-colour fields into sRGB rgba8 bytes.
| arg | type | description |
|---|---|---|
| n | number | |
| r | Field | |
| g | Field | |
| b | Field |
packMask(n: number, r: Field, g: Field, b: Field) → buffer
Pack three linear 0..1 fields into rgba8 bytes (R = AO, G = roughness, B = metallic).
| arg | type | description |
|---|---|---|
| n | number | |
| r | Field | |
| g | Field | |
| b | Field |
packNormal(n: number, h: Field, tile: number, strength: number?) → buffer
Tangent-space normal map from a height field in METRES over a tile of `tile` metres. Raised areas face outward, so a sunk mortar joint or gap reads as a groove; green = image-up (OpenGL / glTF), the convention the engine reads.
| arg | type | description |
|---|---|---|
| n | number | |
| h | Field | |
| tile | number | |
| strength | number? |
cavity(n: number, h: Field, radius: number, depth: number, strength: number?) → Field
Cavity occlusion from height: 1 on tops, darker in pits and grooves. depth in metres for full dark.
| arg | type | description |
|---|---|---|
| n | number | |
| h | Field | |
| radius | number | |
| depth | number | |
| strength | number? |
keepSource(name: string) → any
Re-create a baked texture with a source image beside its GPU data, so tools that read the source image (materialLibraryKit's texture-memory measure) see its real size. Colour and normal maps of 512 px and up keep a JPEG source (quality 95: about a third of the PNG's download, within ~2 code values of it); masks keep a lossless PNG, because they pack independent channels and metallic must stay exactly 0, and so do small and nearest-filtered (pixel, toon) textures. Settings are kept.
| arg | type | description |
|---|---|---|
| name | string |
save(name: string, n: number, bytes: buffer, kind: string, filter: string?) → any
Write rgba8 bytes as a texture asset in the package's textures folder, with a PNG source kept. kind: color | normalMap | mask. filter: linear (default) or nearest.
| arg | type | description |
|---|---|---|
| name | string | |
| n | number | |
| bytes | buffer | |
| kind | string | |
| filter | string? |
Field = { number }Point = { x: number, y: number, w: number, id: number }Cells = {Block = { x0: number, x1: number, y0: number, y1: number, id: number, row: number }BlockMap = {Maps = {Sub-parts
Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.
Problems
Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.
agent_score is exposed.+ 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".
Scoped to this part · feeds back into the world's score.