construction.brick-count
Bricks and mortar for a wall, openings subtracted, for UK standard 215 x 102.5 x 65 mm bricks with 10 mm joints.
1.0.0 · published 2026-10-03 by charlie · Anterra
Pinned by 17 tests, run in TypeScript, Python and Rust.
What it does
Bricks and mortar for a wall of UK standard bricks, with doors and windows subtracted.
## The brick
For example
brickCount(1, 1, , 1, 0%)→ net area square metres 1, bricks 60, mortar cubic metres 0.018 one square metre of half-brick wall is the trade's 60 bricksbrickCount(10, 2.4, openings ×2, 1, 5%)→ net area square metres 20.85, bricks 1,298, mortar cubic metres 0.387 a wall with a door and a window, 5 percent wastagebrickCount(1, 1, , 2, 0%)→ net area square metres 1, bricks 119, mortar cubic metres 0.046 a one-brick wall is 119 bricks a square metre, not 120, and adds a collar joint
The function
The same function in TypeScript, Python and Rust, pinned by the same tests. Pick your language; the choice follows you around the registry.
export function brickCount(wallLength: number, wallHeight: number, openings: readonly Opening[], skins: number, wastageBasisPoints: number): BrickCount
| wallLength | float | metres, more than 0 and at most 1000; taken to the nearest millimetre |
| wallHeight | float | metres, more than 0 and at most 100; taken to the nearest millimetre |
| openings | Opening[] | doors and windows to leave out; may be empty |
| skins | int | 1 for a half-brick wall, 2 for a one-brick wall; 1 to 4 |
| wastageBasisPoints | int | cutting and breakage, applied to bricks and mortar, 500 = 5%; 0 to 10000 |
| returns | BrickCount |
The types it declares, generated into your project
/** A door, window or other hole in the wall, in metres. */
export interface Opening {
readonly width: number;
readonly height: number;
}
/** What to order for the wall. */
export interface BrickCount {
/** the wall face less its openings */
readonly netAreaSquareMetres: number;
/** including wastage, rounded up to whole bricks */
readonly bricks: number;
/** including wastage, rounded up to the whole litre (3 dp) */
readonly mortarCubicMetres: number;
}
Your code names it in one line, in the file that uses it
import { brickCount } from "#fune/construction.brick-count@^1";
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import { roundDiv } from "./math_round_div.ts"; ← from math.round-div ^1.0.0 · built alongside by fune
import { roundFloat } from "./math_round_float.ts"; ← from math.round-float ^1.0.0 · built alongside by fune
import { type BrickCount, type Opening } from "./construction_brick_count_types.ts";
// A 215 x 65 mm brick face plus a 10 mm joint is 225 x 75 mm of wall.
const FACE_MM2 = 225 * 75;
// Mortar per mm2 of wall face, in mm3: each skin fills the joints around a
// brick, (16875 - 215 x 65) / 16875 of the face, 102.5 mm deep, which is
// 2378/135 mm; each collar joint between skins is 10 mm = 1350/135 mm.
const SKIN_MORTAR = 2378;
const COLLAR_MORTAR = 1350;
const MORTAR_DIVISOR = 135;
const MM3_PER_LITRE = 1000000;
function millimetres(value: number, message: string, max: number): number {
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0 || value > max) {
throw new RangeError(`${message} must be a finite number greater than 0 and at most ${max} metres, received ${value}`);
}
return Math.round(roundFloat(value, 3) * 1000);
}
/**
* Bricks and mortar for a wall of UK standard bricks, openings subtracted.
*
* The count is the net face area over one brick's 225 x 75 mm share of it,
* 59.26 per m2 per skin (the trade's "60 a metre"), times the skins, plus
* wastage, rounded up. Mortar is the joint volume that geometry implies.
* Everything is whole millimetres and integer arithmetic.
*/
export function brickCount(
wallLength: number,
wallHeight: number,
openings: readonly Opening[],
skins: number,
wastageBasisPoints: number
): BrickCount {
const length = millimetres(wallLength, "wallLength", 1000);
const height = millimetres(wallHeight, "wallHeight", 100);
if (!Number.isInteger(skins) || skins < 1 || skins > 4) {
throw new RangeError(`skins must be a whole number from 1 to 4, received ${skins}`);
}
if (!Number.isInteger(wastageBasisPoints) || wastageBasisPoints < 0 || wastageBasisPoints > 10000) {
throw new RangeError(`wastageBasisPoints must be a whole number from 0 to 10000, received ${wastageBasisPoints}`);
}
let net = length * height;
openings.forEach((opening, i) => {
const w = millimetres(opening.width, `opening ${i + 1}: width`, 1000);
const h = millimetres(opening.height, `opening ${i + 1}: height`, 1000);
net -= w * h;
});
if (net < 0) {
throw new RangeError("openings are larger than the wall");
}
const bricks = roundDiv(net * skins * (10000 + wastageBasisPoints), FACE_MM2 * 10000, "up");
const perMm2 = skins * SKIN_MORTAR + (skins - 1) * COLLAR_MORTAR;
// Up to the whole litre first, then the wastage, so no product passes 2^53.
const litres = roundDiv(net * perMm2, MORTAR_DIVISOR * MM3_PER_LITRE, "up");
const mortar = roundDiv(litres * (10000 + wastageBasisPoints), 10000, "up");
return {
netAreaSquareMetres: net / 1000000,
bricks,
mortarCubicMetres: mortar / 1000,
};
}Install
fune build
With that line in your source, in a TypeScript project (language typescript in fune.project), fune build resolves it and its 2 dependencies, pins them in fune.lock, downloads only the TypeScript package of each, and builds the code above into your project’s .fune/build, one readable file per capability with a header linking back here. Or pin a range in fune.project and build in one step:
fune add construction.brick-count
The manifest, vectors and README with only the TypeScript implementation. Install it without the registry with fune add ./construction.brick-count-1.0.0-typescript.fune, or fetch it from a terminal with fune pull construction.brick-count@1.0.0:typescript.
The whole function, every language, is one file too: construction.brick-count-1.0.0.fune, 19,874 bytes, sha256 4c520d53927a6f63aa67ea0907846e0323782667d63ef704067c362ffc799a8f. It installs into a project of any language.
Customise it in your app
The seams this capability offers. Put a marker directly above a function of your own and fune build wires it into the built code; the package on the registry is not changed, the built file’s header lists it under CUSTOMISED, and fune hooks lists every hook in the project. How hooks work.
before — your function gets the arguments and returns them, changed or not, or throws to refuse the call.
// fune: before construction.brick-count
after — your function gets the result and the arguments, and returns the final result.
// fune: after construction.brick-count
replace — inside this capability’s code only, calls to a dependency go to your function, with the same signature. Other capabilities that use it are unaffected; write in * to replace it everywhere.
// fune: replace math.round-div in construction.brick-count
// fune: replace math.round-float in construction.brick-count
step — your function runs at a numbered point inside the function’s body, receives the in-scope values it names as parameters, and may return replacements. List the points with fune show construction.brick-count --steps.
// fune: step construction.brick-count after <n|label>
Tests
A version published now needs at least 8 tests for every function, and one that expects the error for each function that throws; the registry refuses it otherwise. fune verify --all runs each case in TypeScript, Python and Rust, and a project runs them again with fune verify. This page lists the cases; it does not run them. The exact JSON is vectors.json.
| Case | Arguments | Expected | |
|---|---|---|---|
| one square metre of half-brick wall is the trade's 60 bricks | 1, 1, , 1, 0% | → | net area square metres 1, bricks 60, mortar cubic metres 0.018 |
| a wall with a door and a window, 5 percent wastage | 10, 2.4, openings ×2, 1, 5% | → | net area square metres 20.85, bricks 1,298, mortar cubic metres 0.387 |
| a one-brick wall is 119 bricks a square metre, not 120, and adds a collar joint | 1, 1, , 2, 0% | → | net area square metres 1, bricks 119, mortar cubic metres 0.046 |
| exactly 100 bricks plus 10 percent is exactly 110 | 2.25, 0.75, , 1, 10% | → | net area square metres 1.688, bricks 110, mortar cubic metres 0.033 |
| a garden wall that comes out to exactly 336 bricks with wastage | 6, 0.9, , 1, 5% | → | net area square metres 5.4, bricks 336, mortar cubic metres 0.101 |
| three skins | 1, 1, , 3, 0% | → | net area square metres 1, bricks 178, mortar cubic metres 0.073 |
| dimensions are taken to the nearest millimetre | 3, 1, , 1, 0% | → | net area square metres 3, bricks 178, mortar cubic metres 0.053 |
| an opening the size of the wall leaves nothing to build | 2, 1, openings ×1, 1, 5% | → | net area square metres 0, bricks 0, mortar cubic metres 0 |
| openings larger than the wall are an error | 2, 1, openings ×1, 1, 0% | → | error: openings are larger than the wall |
| no skins is an error | 1, 1, , 0, 0% | → | error: skins must be a whole number from 1 to 4 |
Show the other 7 tests
| Case | Arguments | Expected | |
|---|---|---|---|
| five skins is an error | 1, 1, , 5, 0% | → | error: skins must be a whole number from 1 to 4 |
| a fractional skin count is an error | 1, 1, , 1.5, 0% | → | error: skins must be a whole number from 1 to 4 |
| a zero-length wall is an error | 0, 1, , 1, 0% | → | error: wallLength must be a finite number greater than 0 and at most 1000 metres |
| a wall over 100 metres high is an error | 5, 101, , 1, 0% | → | error: wallHeight must be a finite number greater than 0 and at most 100 metres |
| a negative opening is an error | 5, 2, openings ×1, 1, 0% | → | error: opening 1: width must be a finite number greater than 0 and at most 1000 metres |
| negative wastage is an error | 1, 1, , 1, -0.01% | → | error: wastageBasisPoints must be a whole number from 0 to 10000 |
| fractional wastage is an error | 1, 1, , 1, 0.025% | → | error: wastageBasisPoints must be a whole number from 0 to 10000 |
More from the author
A UK metric brick is 215 × 102.5 × 65 mm (work size). Laid with 10 mm joints it occupies 225 × 75 mm of wall face (the coordinating size), so one square metre of a half-brick (single-skin) wall takes 1,000,000 / 16,875 = 59.26 bricks, which the trade calls "60 a metre". A one-brick wall (two skins) is twice that, 118.5, so 119 for a square metre rather than the 120 that doubling the rounded figure gives.
## How it is worked out
1. Wall and openings, given in metres, are taken to the nearest millimetre; the net face area is the wall less the openings, in whole mm². 2. **Bricks** = net area × skins × (1 + wastage) ÷ 16,875 mm², rounded up. 3. **Mortar** is the joint volume the geometry implies, not a rule of thumb: per skin, the joints are (16,875 − 215 × 65) / 16,875 of the face, 102.5 mm deep, which is 17.6 litres per m²; each collar joint between skins adds a 10 mm layer, 10 litres per m². Rounded up to a whole litre, then the wastage added and rounded up to a litre again.
All arithmetic is in integers after step 1, so it does not suffer from floating-point ceilings.
## What it does not count
Frogs and perforations (a frog-up brick takes more mortar; add it to the wastage), cavity walls built with a block inner leaf (count the brick skin here, blocks separately), ties, lintels, piers and returns, and the bond: English and Flemish bond one-brick walls use the same number of bricks per m² as two stretcher skins, but headers change how many facing bricks you need.
Limits: length up to 1000 m, height up to 100 m, 1 to 4 skins, wastage 0 to 10,000 basis points. Openings larger than the wall are an error; openings equal to it leave nothing to build.
## Sources
- BS EN 771-1 (clay masonry units) and the UK standard format of 215 × 102.5 × 65 mm with a 225 × 112.5 × 75 mm coordinating size; see "Brick sizes", Designing Buildings Wiki, https://www.designingbuildings.co.uk/wiki/Brick_sizes - The 60 bricks per m² single-skin rule as used in the UK trade, e.g. https://www.imperialbricks.co.uk/guidance/bricks-per-m2-guide/
Files
| Path | Bytes |
|---|---|
| README.md | 2,227 |
| impl/python.py | 3,006 |
| impl/rust.rs | 3,842 |
| impl/typescript.ts | 2,842 |
| vectors.json | 4,191 |