ParaShape

Expression

Every field is a JavaScript expression. The Math page covers the everyday 90%; this page is the complete reference.

(width - gap * (n - 1)) / n      // arithmetic
open ? 0 : depth                 // a choice
sizes.map(s => s + clearance)    // a list
Math.max(a, b, c)                // a library call

Operators

GroupOperators
Arithmetic+ - * / % **
Compare< <= > >= == === != !==
Logical&& || !
Choicecond ? a : b

Standard library

Available globals: Math, Number, String, Array, Object, Boolean, parseInt, parseFloat, isNaN.

Math (MDN →)

Method / ConstantDescriptionExample → result
Math.PIπ ≈ 3.14159Math.PI * r * r
Math.Ee ≈ 2.71828Math.exp(1)
Math.abs(x)Absolute valueMath.abs(-5) → 5
Math.ceil(x)Round upMath.ceil(4.1) → 5
Math.floor(x)Round downMath.floor(4.9) → 4
Math.round(x)Round to nearestMath.round(4.5) → 5
Math.trunc(x)Drop decimal partMath.trunc(-4.9) → -4
Math.sign(x)-1 / 0 / +1Math.sign(-3) → -1
Math.min(a, b, …)Smallest valueMath.min(3, 1, 2) → 1
Math.max(a, b, …)Largest valueMath.max(3, 1, 2) → 3
Math.sqrt(x)Square rootMath.sqrt(9) → 3
Math.cbrt(x)Cube rootMath.cbrt(27) → 3
Math.pow(x, y)x to the power y (same as x**y)Math.pow(2, 10) → 1024
Math.hypot(a, b, …)√(a²+b²+…) — diagonalMath.hypot(3, 4) → 5
Math.sin(rad)Sine (input in radians)Math.sin(Math.PI/2) → 1
Math.cos(rad)Cosine (radians)Math.cos(0) → 1
Math.tan(rad)Tangent (radians)Math.tan(Math.PI/4) → 1
Math.asin(x)Arcsine → radiansMath.asin(1) → 1.5708
Math.acos(x)Arccosine → radiansMath.acos(0) → 1.5708
Math.atan(x)Arctangent → radiansMath.atan(1) → 0.7854
Math.atan2(y, x)Angle of vector (y,x) → radiansMath.atan2(1,1) → 0.7854
Math.log(x)Natural log ln(x)Math.log(Math.E) → 1
Math.log2(x)Log base 2Math.log2(8) → 3
Math.log10(x)Log base 10Math.log10(1000) → 3
Math.exp(x)Math.exp(1) → 2.71828

Number (MDN →)

Method / ConstantDescriptionExample → result
Number.isFinite(x)true if finite numberNumber.isFinite(1/0) → false
Number.isInteger(x)true if whole numberNumber.isInteger(3.0) → true
Number.isNaN(x)true if exactly NaN (no coercion)Number.isNaN(NaN) → true
Number.MAX_SAFE_INTEGER2⁵³ − 1 = 9007199254740991Number.MAX_SAFE_INTEGER
Number.EPSILONSmallest float difference ≈ 2.2e-16Number.EPSILON
n.toFixed(d)String with d decimal places(1.005).toFixed(2) → "1.00"
n.toPrecision(d)String with d significant digits(123.45).toPrecision(4) → "123.5"
n.toString(radix?)Number as string, optional base(255).toString(16) → "ff"

String (MDN →)

Method / PropertyDescriptionExample → result
s.lengthCharacter count"abc".length → 3
s.toUpperCase()All uppercase"abc".toUpperCase() → "ABC"
s.toLowerCase()All lowercase"ABC".toLowerCase() → "abc"
s.trim()Remove leading/trailing whitespace" hi ".trim() → "hi"
s.includes(sub)true if substring present"shelf".includes("el") → true
s.startsWith(sub)true if starts with sub"shelf".startsWith("sh") → true
s.endsWith(sub)true if ends with sub"shelf".endsWith("lf") → true
s.indexOf(sub)Position of first match, -1 if none"shelf".indexOf("e") → 2
s.slice(start, end?)Extract [start, end)"shelf".slice(1,3) → "he"
s.replace(a, b)Replace first occurrence"aab".replace("a","x") → "xab"
s.replaceAll(a, b)Replace all occurrences"aab".replaceAll("a","x") → "xxb"
s.split(sep)Split into array"a,b".split(",") → ["a","b"]
s.repeat(n)Repeat n times"ab".repeat(3) → "ababab"
s.padStart(len, ch)Pad left to length"5".padStart(3,"0") → "005"
s.padEnd(len, ch)Pad right to length"5".padEnd(3,"0") → "500"

Array (MDN →)

Method / PropertyDescriptionExample → result
arr.lengthNumber of elements[1,2,3].length → 3
arr.map(fn)New array: fn applied to each element[1,2,3].map(x=>x*2) → [2,4,6]
arr.filter(fn)New array: only elements where fn is true[1,2,3].filter(x=>x>1) → [2,3]
arr.reduce(fn, init)Fold to single value[1,2,3].reduce((a,b)=>a+b,0) → 6
arr.find(fn)First element where fn is true[1,2,3].find(x=>x>1) → 2
arr.findIndex(fn)Index of first match, -1 if none[1,2,3].findIndex(x=>x>1) → 1
arr.some(fn)true if any element passes fn[1,2,3].some(x=>x>2) → true
arr.every(fn)true if all elements pass fn[1,2,3].every(x=>x>0) → true
arr.includes(v)true if value exists in array[1,2,3].includes(2) → true
arr.indexOf(v)Index of first match, -1 if none[1,2,3].indexOf(2) → 1
arr.slice(s, e?)Copy subarray [s, e)[1,2,3].slice(1) → [2,3]
arr.concat(b)Join two arrays (non-mutating)[1,2].concat([3,4]) → [1,2,3,4]
arr.join(sep)Join elements as string[1,2,3].join("-") → "1-2-3"
arr.flat(depth?)Flatten nested arrays[[1,2],[3]].flat() → [1,2,3]
arr.flatMap(fn)map then flat(1)[1,2].flatMap(x=>[x,x*2]) → [1,2,2,4]
arr.sort(fn?)Sort (pass (a,b)=>a-b for numbers)[3,1,2].sort((a,b)=>a-b) → [1,2,3]
arr.reverse()Reverse in place[1,2,3].reverse() → [3,2,1]
Array.from({length:n}, fn)Create array of length n via fn(_, i)Array.from({length:3},(_,i)=>i) → [0,1,2]
Array.isArray(v)true if value is an arrayArray.isArray([1,2]) → true

Object (MDN →)

MethodDescriptionExample → result
Object.keys(obj)Array of own property keysObject.keys({a:1,b:2}) → ["a","b"]
Object.values(obj)Array of own property valuesObject.values({a:1,b:2}) → [1,2]
Object.entries(obj)Array of [key, value] pairsObject.entries({a:1}) → [["a",1]]
Object.assign(target, src)Copy src properties into targetObject.assign({a:1},{b:2}) → {a:1,b:2}
Object.fromEntries(pairs)Build object from [[key,val], …]Object.fromEntries([["a",1]]) → {a:1}

parseInt · parseFloat · isNaN · Boolean (MDN →)

FunctionDescriptionExample → result
parseInt(s, radix?)Parse integer from string (radix default 10)parseInt("42px") → 42
parseFloat(s)Parse float from stringparseFloat("3.14abc") → 3.14
isNaN(v)true if NaN after coercionisNaN("abc") → true
Boolean(v)Falsy: 0 "" null undefined NaNBoolean(0) → false

Selecting faces & edges

Edge Fillet, Face Extrude etc. take a filter arrow instead of an index:

(points, normal) => normal[2] > 0.9   // Face Extrude — only the top
(p1, p2) => p1[2] > 0 && p2[2] > 0    // Edge Fillet — only top edges

Not supported

Not availableUse instead
if … elsecond ? a : b
for / whilearr.map / filter / reduce
function () {}x => x * 2
let / const / =read-only — no assignment
...spread ?? \template``not parsed by the expression engine
console · Date · RegExp · JSONnot in scope