I'm playing around with base64 embedded data URI's and tried to analyze the buffer data of the gltf box sample model, as defined in this example here (line 76).


This is the buffer data for a simple cube, here's screenshot:

enter image description here

But it's giving me a hard time to understand what's exactly in this buffer. As far as I know, it should contain the vertices, and maybe indices.

I tried to decode the base64 and the output is binary. I'm lost since I have no clue how this binary is encoded or decoded. Can anyone point me how to write such buffers or at least how to read them?

How do I generate my own buffers?

  • $\begingroup$ check out this answer to know how to encode the buffer data as mentioned in the above question $\endgroup$
    – Gangula
    Commented Nov 7, 2022 at 21:45

2 Answers 2


The information you're looking for is defined in the 'accessors' and 'bufferViews' near the top of the source file you linked.

Bufferviews simply divide the buffer up into sub ranges and define broadly what kind of data lives there using some obscure shortcodes. In this case, target 34963 means index data and 34962 means vertex data. So from the other parameters in the bufferviews you can see that the first 72 bytes are indices and the remaining 576 bytes are vertex data.

The accessors are what actually define the format of the data and again use weird codes for "componentType" - 5123 is an unsigned short (2 bytes) and 5126 is single precision float (4 bytes). They also define whether they should be read singly ("SCALAR") or in vector groups (e.g. "VEC3"), and also a starting offset into the bufferview and "stride" between the start of data points like regular OpenGL vertex buffer bindings.

Putting it all together, the first 72 bytes are 36 shorts representing the indices (3 * 12 triangles). The next 576 bytes are two consecutive sets of 24 vec3 (4 per square face, 12 bytes per vec3) representing vertex data. Since the first set are clamped to + or - 1/2 and the second set to + or - 1, I'm guessing first set are positions, second set are normals.

The base 64 encoding just takes the raw bit stream, splits it into groups of 6 rather than 8, and maps each unique 6-bit combination onto a character. You can see this is quite wasteful as each character takes at least 8 bits to store, quite possibly 16 or more depending on the encoding used.

  • $\begingroup$ Normals, gotcha. $\endgroup$
    – q9f
    Commented Jun 15, 2016 at 12:33

In addition to @russ' answer, I was able to decode the buffer with the gltf Utilities.


  function(buf) {
    let idx = new DataView(buf, 0, 72);
    for (var i = 0; i < 72; i += 2) {
      window.console.log(idx.getUint16(i, true));
    let vtx = new DataView(buf, 72, 288);
    for (var v = 0; v < 288; v += 4) {
      window.console.log(vtx.getFloat32(v, true));
  function(xhr) {
    window.console.log("The ArrayBuffer failed to load");

Here is a JSfiddle to test. loadArrayBuffer() creates a JavaScript ArrayBuffer from the base64 encoded String.

Opening the ArrayBuffer with a JavaScript DataView allows to read the buffer data. Note the first 72 bytes are 36 unsigned short indeces (Uint16) and the following 288 bytes are the 72 float vertices (Float32).

I didn't read the normals (last 288 bytes), but that would work similar to the vertices.

And to encode a base64 string with my custom buffers, I'll just do it vice versa. Here is a JSfiddle for encoding.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.