# @novorender/api

[![Latest NPM Version](https://img.shields.io/npm/v/@novorender/api.svg?label=@novorender/api)](https://www.npmjs.com/package/@novorender/api)

This package contains all the various APIs relevant for developing a Novorender web app.

## Getting Started

Install `@novorender/api` using your favorite package manager.

`npm i @novorender/api`

This npm package contains pre-built [ESM](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) bundle and typescript definitions. It is meant to be used with modern javascript bundlers such as [vite](https://vitejs.dev/) or [webpack](https://webpackjs.org/) or directly in a modern browser.

> Avoid [deep imports](https://gist.github.com/daleyjem/0f38f561a4e91e58eba580889f38330f)! Everything you need should be available from the package root: `@novorender/api`.

## Development

To build the package, run the following command:

```bash
npm run build
```

This will create a `dist` folder with the following files:

- `novorender-api.js` - the main ESM bundle
- `novorender-api.d.ts` - the TypeScript definitions

To run the build in a watch mode, use:

```bash
npm run build:watch
```

This will watch for changes and rebuild the package automatically.

To lint and automatically fix the code with `eslint`:

```bash
npm run lint
```

To format the code using `prettier`:

```bash
npm run fmt
```

The package is using pre-commit hooks in order to lint and format the code before committing. This is done using `husky` and `lint-staged`.

## Dependencies

We use [gl-matrix](https://www.npmjs.com/package/gl-matrix) for linear algebra.

> Double precision matrices `glMatrix.setMatrixArrayType(Array)` are required. Don't change back to `Float32Array`!

## Server requirements

Our API uses advanced, cutting edge JavaScript APIs, many of which come with certain security requirements. In general, the following two global properties have to be true: [`globalThis.isSecureContext`](https://developer.mozilla.org/en-US/docs/Web/API/isSecureContext) and [`globalThis.crossOriginIsolated`](https://developer.mozilla.org/en-US/docs/Web/API/crossOriginIsolated).

To make it all work, your server has to ensure:

1. A [secure context](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts). In practice, this means HTTP on localhost (for debugging only) and HTTPS everywhere else, including LAN.

2. Cross origin [HTTP headers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements) for _top level documents_.

```http
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
```

3. Correct MIME types - [`text/javascript`](https://www.iana.org/assignments/media-types/text/javascript) for JavaScript files and [`application/wasm`](https://www.iana.org/assignments/media-types/application/wasm) for WebAssembly files.

4. Any resources loaded from a separate domain have to be configured with [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) to allow your domain.

5. The service workers script should be at the appropriate location, preferably at the root of your domain. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register) for more.

## Usage

A minimal app might look something like this:

```typescript
import { View, getDeviceProfile } from "@novorender/api";

async function main(canvas: HTMLCanvasElement) {
  const gpuTier = 2; // laptop with reasonably new/powerful GPU.
  const deviceProfile = getDeviceProfile(gpuTier);
  const view = await View.create(canvas, deviceProfile);
  await view.run();
  view.dispose();
}

main(document.getElementById("render_canvas"));
```

If everything succeeds, this should render an image with a minor gradient of gray. To make it a little more interesting, we can change the `RenderState` to include a grid.

```typescript
// ... snip...
const view = await View.create(canvas, deviceProfile);
view.modifyRenderState({ grid: { enabled: true } });
await view.run();
// ...snip...
```

The view already has camera controller built in, so you can move around and enjoy your grid with the mouse and/or keyboard, or even touch gestures.

> The view will automatically resize your canvas' pixel size when the css layout and/or the render state output settings changes.
> This could lead to a runaway recursive feedback loop.
> To avoid this issue, you must assign a css width and height to your canvas!

```html
<canvas style="width: 100%; height: 100%;"></canvas>
```

## Next steps

Getting that first view up and running is an important step. Now you can actually start to make your application. Please see the [documentation](https://docs.novorender.com) for tutorials, examples and a detailed reference manual!
