# SDF-2D - v0.7.6

# Documentation

The motivation behind this library and more in-depth information about the rendering techniques utilised can be found in my thesis.

## Links

- Repository
- Demo
- Minimal example
- More complex example
- Source code of the demo

## Usage (1st option)

- To start using cutting-edge 2D graphics, you first need a renderer instance. You can get one by calling the compile function.
  - For this, you have to provide one or more DrawableDescriptors.
  - Optionally, the default compile settings can be overridden using StartupSettings.
- Once you have a renderer, you can start drawing objects through the Renderer interface.

## Usage (2nd option)

If you're planning to create animated content, use the runAnimation function to save yourself from writing boilerplate code. See its documentation for more details.

## Extending drawables

> Iñigo Quilez has a great collection of 2D SDFs

- Subclass Drawable
- Implement its abstract methods
- Add a static `descriptor` property of type DrawableDescriptor to your class
- Follow the instructions given in Usage

## Useful to know

### Math

The `vec2`, `vec3`, and `vec4` types seen in the documentation come from the glMatrix library and are equivalent to regular JS Arrays or Float32Arrays, so feel free to pass `[x, y]` to functions that expect a `vec2`.

### Coordinates

Wherever positions need to be specified, the `y` axis grows upwards. This means that when you set the view area, the origin is at the bottom-left corner of the display.

### Tile-based rendering

To optimise the evaluation of the distance field, the display is divided into a grid of tiles. The shaders for each tile are compiled to support a fixed maximum number of objects. When using the built-in drawables, this means that beyond a certain number of on-screen objects, new ones may stop appearing.

Mitigating this is easy. Instead of the following code:

    this.renderer = await compile(canvas, [Circle.descriptor, CircleLight.descriptor]);

modify it to something like this:

    this.renderer = await compile(canvas, [
      {
        ...Circle.descriptor,
        shaderCombinationSteps: [0, 1, 2, 24, 64],
      },
      {
        ...CircleLight.descriptor,
        shaderCombinationSteps: [0, 1, 2, 4],
      },
    ]);

Using very large numbers is not advised, for both compatibility and performance reasons.

> Steps are especially useful for tile-based rendering: at any given moment, one tile may be empty or contain just a few objects, while another holds a large cluster. The compiled shaders only account for the number of objects actually present on each tile.