---
url: /examples/basics/indices.md
description: Draw indexed geometry by reusing vertex data through an index buffer.
---

::: example-editor

```ts
import { glCanvas } from "@radiancejs/gl";
import fragment from "./mesh.frag?raw";
import vertex from "./mesh.vert?raw";
import "./styles.css";

// A grid of (N + 1)² vertices, each reused by up to 6 triangles
// thanks to the index buffer.
const N = 30;

const positions: number[] = [];
const indices: number[] = [];

for (let y = 0; y <= N; y++) {
  for (let x = 0; x <= N; x++) {
    positions.push((x / N) * 2 - 1, (y / N) * 2 - 1);

    // a cell can only be emitted once its four corners exist,
    // which is the case everywhere except on the last row/column
    if (x < N && y < N) {
      const i = y * (N + 1) + x;
      // both triangles end on the same corner so flat shading
      // gives one color per cell instead of a diagonal seam
      indices.push(i, i + 1, i + N + 1, i + 1, i + N + 2, i + N + 1);
    }
  }
}

glCanvas({
  canvas: "#glCanvas",
  vertex,
  fragment,
  attributes: {
    aPosition: { size: 2, data: positions },
    index: { size: 1, data: indices },
  },
  uniforms: {
    uTime: ({ time }) => time / 1000,
  },
  depthTest: true,
});

```

```vert
attribute vec2 aPosition;
uniform float uTime;
// flat interpolation: every fragment of a triangle gets the color
// computed at its provoking vertex, ignoring interpolation
flat varying vec3 vColor;

// 3d gaussian bump
float gaussianHeight(vec2 p) {
  return exp(-dot(p, p) * .18) * (.85 + .15);
}

// cosine color palette
vec3 palette(float t) {
  return vec3(.42, .36, .55) + vec3(.38, .34, .38) * cos(6.28318 * (vec3(1., .9, .7) * t));
}

mat4 translation(vec3 t) {
  return mat4(1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., t.x, t.y, t.z, 1.);
}

mat4 rotationX(float a) {
  float c = cos(a), s = sin(a);
  return mat4(1., 0., 0., 0., 0., c, -s, 0., 0., s, c, 0., 0., 0., 0., 1.);
}

mat4 rotationY(float a) {
  float c = cos(a), s = sin(a);
  return mat4(c, 0., -s, 0., 0., 1., 0., 0., s, 0., c, 0., 0., 0., 0., 1.);
}

mat4 perspective(float fov, float aspect, float near, float far) {
  float f = 1. / tan(fov * .5);
  return mat4(
    f / aspect, 0., 0., 0.,
    0., f, 0., 0.,
    0., 0., (far + near) / (near - far), -1.,
    0., 0., 2. * far * near / (near - far), 0.
  );
}

void main() {
  vec2 p = aPosition * 5.;
  float h = gaussianHeight(p);

  mat4 model = rotationY(uTime * .15);
  mat4 view = translation(vec3(0., -.4, -4.)) * rotationX(radians(-10.));
  mat4 projection = perspective(radians(40.), 1., .1, 20.);

  vec4 world = model * vec4(aPosition.x, h, aPosition.y, 1.);
  gl_Position = projection * view * world;

  vColor = palette(h * 0.8 + .5);
}

```

```frag
flat varying vec3 vColor;

void main() {
  gl_FragColor = vec4(vColor, 1.);
}

```

```css
html {
  color-scheme: light dark;
}

body {
  margin: 0;
  height: 100svh;
  display: grid;
  place-items: center;
}

canvas {
  width: min(90svmin, 900px);
  aspect-ratio: 1;
  display: block;
  border-radius: 8px;
  border: 1px solid rgb(128 128 128 / 0.4);
}

```

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>RadianceJS Example</title>
  </head>
  <body>
    <canvas id="glCanvas"></canvas>
    <script src="/index.ts"></script>
  </body>
</html>

```

:::
