import {DeviceTabs} from '@site/src/react-luma';
import {HelloTriangleExample} from '@site';

# Hello Triangle

This tutorial will demonstrate how to draw a triangle using luma.gl's high-level APIs.

<DeviceTabs />
<HelloTriangleExample />

It is assumed you've set up your development environment as described in
[Getting Started](/docs/getting-started). Your `index.js` file should look like the following:

```typescript
import {AnimationLoop} from '@luma.gl/engine';
import {clear} from '@luma.gl/webgl';

class AppAnimationLoop extends AnimationLoop ({
  override onInitialize({device}) {
    // Setup logic goes here
  },

  override onRender({device}) {
    // Drawing logic goes here
    clear(device, {color: [0, 0, 0, 1]});
  }
});

const loop = new AppAnimationLoop();
loop.start();
```

First, we'll need to update our imports with the classes we'll be using, `Buffer` and `Model`:

```typescript
import {AnimationLoop, Model} from '@luma.gl/engine';
import {clear} from '@luma.gl/webgl';
```

Now let's create some buffers in the `onInitialize` method to hold our attribute data:

```typescript
  override onInitialize({device}) {
    // Setup logic goes here
    const positionBuffer = device.createBuffer(new Float32Array([
      -0.5, -0.5,
      0.5, -0.5,
      0.0, 0.5
    ]));

    const colorBuffer = device.createBuffer(new Float32Array([
      1.0, 0.0, 0.0,
      0.0, 1.0, 0.0,
      0.0, 0.0, 1.0
    ]));
  }
```

Next let's add the vertex and fragment shader code we'll be using to draw:

```typescript
  override onInitialize({device}) {
    // Setup logic goes here

    // Buffers...

    const vs = `
      attribute vec2 position;
      attribute vec3 color;

      varying vec3 vColor;

      void main() {
        vColor = color;
        gl_Position = vec4(position, 0.0, 1.0);
      }
    `;

    const fs = `
      varying vec3 vColor;

      void main() {
        gl_FragColor = vec4(vColor, 1.0);
      }
    `;

  }
```

As a final step in our initialization, we'll create a `Model` in `onInitialize`:

```typescript
  override onInitialize({device}) {
    // Setup logic goes here

    // Buffers...

    // Shaders...

    this.model = new Model(device, {
      vs,
      fs,
      attributes: {
        position: positionBuffer,
        color: colorBuffer
      },
      vertexCount: 3
    });

    return {model};
  }
```

A `Model` can be thought of as gathering all the WebGL pieces necessary for a single draw call: programs, attributes, uniforms. Also note that we return the `Model` instance we created. This will make it available to the `onRender` method.

Our `onRender` method is comparitavely much simpler:

```typescript
  override onRender({device}) {
    clear(device, {color: [0, 0, 0, 1]});
    this.model.draw();
  }
```

This clears the canvas and draws the `Model`. If all went well, you should see a tri-color triangle on a black background.

The entire application should look like the following:

```typescript
import {AnimationLoop, Model} from '@luma.gl/engine';
import {clear} from '@luma.gl/webgl';

class AppAnimationLoop extends AnimationLoop {
  override onInitialize({device}) {
    const positionBuffer = device.createBuffer(new Float32Array([-0.5, -0.5, 0.5, -0.5, 0.0, 0.5]));

    const colorBuffer = device.createBuffer(new Float32Array([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]));

    const vs = `
      attribute vec2 position;
      attribute vec3 color;

      varying vec3 vColor;

      void main() {
        vColor = color;
        gl_Position = vec4(position, 0.0, 1.0);
      }
    `;

    const fs = `
      varying vec3 vColor;

      void main() {
        gl_FragColor = vec4(vColor, 1.0);
      }
    `;

    const model = new Model(device, {
      vs,
      fs,
      attributes: {
        position: positionBuffer,
        color: colorBuffer
      },
      vertexCount: 3
    });

    return {model};
  },

  override onRender({device, model}) {
    clear(device, {color: [0, 0, 0, 1]});
    model.draw();
  }
};

const loop = new AppAnimationLoop();
loop.start();
```
