A *surface* is essentially a 2D array. Currently, only floating-point values are supported, although hopefully colors and integers will be added in the near future.

A surface can be either *infinite* or *finite*. An infinite surface is one that has its `width`

and `height`

fields equal to infinity.

A surface may or may not be *writable*. Writable surfaces have a `.set()`

method which can be used to set the value of a specific cell. Non-writable surfaces have no such method.

Most surface operations are *lazy*, in that they perform the operation only as needed, when values are requested via `.get()`

. Some operations are *strict*, and must compute the operation over *every* cell in the input. Strict operations have method names ending with `$`

.

`.render(`

(Flextime instance method)
*surface*)

Renders a surface to the canvas, as a grayscale image (0.0 is black and 1.0 is white).

### Surface constructors

`Surface.nil()`

Constructs the null surface, an infinite non-writable surface which returns 0.0 everywhere.

`Surface.constant(`

*c*)

Constructs an infinite, non-writable surface with the valueceverywhere.

`Surface.func(`

*f,width,height*)

Constructs a non-writable surface that evaluates the functionf(x,y)to determine the value at pointx,y. If awidthandheightare provided the surface will be finite, otherwise it will be infinite.

`Surface.array(`

*arr,width,height*)

Constructs a surface from an existing`Float32Array`

. Note that the length of the array must equalwidth*height.

### Surface instance methods

Most surface instance methods are chainable, except for those that return usable values (such as `.get()`

).

`.get(`

*x,y*)

`Returns the value in the surface at the point ``(x,y)`

.

`.set(`

*x,y,v*)

Sets the value in the surface at`(x,y)`

tov. Not valid on non-writable surfaces.

`.build$([`

Forces strictness of the surface. This method will create a new array surface of the required size and store the computed values of every cell into it. The optional width and height arguments are required when building an infinite surface.
*w,h*])

#### Value transformations

These operations apply some transformation to the*values*in each cell; the transformation is purely local, and does not depend on the location of the cell or the values in neighboring cells. Consequently, most of these methods preserve the infinite/finite nature of the inputs.

`.map(`*f*[,*f'*])

Returns the surface that results from applying the functionfto the values in the input surface. Optionally, an inverse functionf'can be specified as the second argument; if present, then the resulting surface will be writable, if its input is, with written values passed throughf'.

`.scale(`

*s*)

Returns a possibly-writable surface that results from multiplying all the values in the input bys. (When setting values, the value will be divided bys.)

`.offset(`

*o*)

Returns a possibly-writable surface that results from addingoto all the values in the input. (When setting values,owill be subtracted from the value.)

`.threshold(`

*t*)

Returns the result of thresholding the input surface to 0.0 or 1.0 by the thresholdt, which defaults to 0.5.

`.clamp(`

*low,high*)

Returns the result of clamping the input values to the rangelow...high, inclusive.

#### Geometry transformations

These methods affect the geometry of the incoming surface, but not its values.

`.translate(`

*dx,dy*)

Returns the surface, translated bydx,dy. That is, a`.get(x,y)`

on the output is translated into`.get(x+dx,y+dy)`

on the input.

`.subsurf(`

*x1,y1,x2,y2*)

Returns a subsurface of the input surface. The resulting surface will be finite, withwidth= 1 +x2-x1andheight= 1 +y2-y1. In the subsurface, the point0,0will map tox1,y1in the input.