gltf
stableBuild and inspect glTF/GLB 3D scene data: parse binary headers, create meshes, materials, nodes, and 4x4 transform matrices.
use plugin gltf Plugin snippets can be edited in the Playground, but native capabilities are executed locally with the Zolo CLI.
Functions (13)
- parse_gltf_header Parse magic, version, length from GLB bytes
- create_mesh Build a mesh descriptor from vertices and indices
- create_material Build a PBR material descriptor
- transform_identity Return a 4x4 identity matrix
- parse_glb_chunks List JSON and BIN chunks inside a GLB file
- create_node Build a scene node with optional transform and mesh
- create_scene Build a scene descriptor from a name and node list
- create_accessor_info Build a glTF accessor descriptor
- create_buffer_view Build a glTF bufferView descriptor
- transform_translate Build a translation matrix
- transform_scale Build a scale matrix
- transform_rotate_y Build a Y-axis rotation matrix
- multiply_transforms Multiply two 4x4 column-major matrices
From import to result
- 01Import only what you use
- 02Copy the smallest example
- 03Run it with the Zolo CLI
Overview¶
gltf is a toolkit for constructing and inspecting glTF/GLB 3D scene data
without pulling in a full asset library. Every builder function returns a plain
table that mirrors the glTF JSON schema (nodes, scenes, meshes, materials,
accessors, bufferViews), so the values are easy to inspect, serialize, or feed
into a renderer. There is no hidden state or opaque handle: a transform is just a
16-element table holding a column-major 4x4 matrix, and a mesh is a table of
counts plus flat vertex and index lists.
Reach for it in two situations: when you need to read the binary structure of a
.glb file (parse_gltf_header and parse_glb_chunks decode the magic, version,
and JSON/BIN chunk layout), and when you are assembling scene data by hand. The
transform_* and multiply_transforms helpers let you compose translation,
rotation, and scale into a single matrix that you can attach to a node.
Common patterns¶
Build a mesh, wrap it in a node, and collect the nodes into a scene:
use plugin gltf::{create_mesh, create_node, create_scene}
let verts = [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.5, 1.0, 0.0]
let mesh = create_mesh(verts, [0, 1, 2])
let node = create_node("Triangle", [0.0, 0.0, 0.0], nil, [1.0, 1.0, 1.0], 0)
let scene = create_scene("Main", [node])
print("{scene["name"]} has a mesh with {mesh["vertex_count"]} vertices")Compose a transform by multiplying translate, rotate, and scale matrices:
use plugin gltf::{transform_translate, transform_rotate_y, transform_scale, multiply_transforms}
let t = transform_translate(0.0, 2.0, 0.0)
let r = transform_rotate_y(1.5708)
let s = transform_scale(2.0, 2.0, 2.0)
let world = multiply_transforms(multiply_transforms(t, r), s)
print("translation x lives at index 12: {world[12]}")Decode a GLB binary header and walk its chunks:
use plugin gltf::{parse_gltf_header, parse_glb_chunks}
let header = parse_gltf_header(file_bytes)
print("{header["magic"]} v{header["version"]} ({header["length"]} bytes)")
let chunks = parse_glb_chunks(file_bytes)
for chunk in chunks {
print("{chunk["type"]} chunk at {chunk["offset"]}, {chunk["length"]} bytes")
}Parse magic, version, length from GLB bytes
Reads the first 12 bytes of a GLB binary and returns a table with magic ("glTF" or hex string), version, and length.
use plugin gltf::{parse_gltf_header}
let header = parse_gltf_header(file_bytes)
print("{header["magic"]} v{header["version"]}, {header["length"]} bytes")A non-"glTF" magic comes back as a hex string, which makes it easy to reject
files that are not valid GLB binaries:
use plugin gltf::{parse_gltf_header}
let header = parse_gltf_header(file_bytes)
if header["magic"] != "glTF" {
print("not a GLB file (magic was {header["magic"]})")
}Build a mesh descriptor from vertices and indices
Packages a flat list of XYZ vertex coordinates and a list of integer indices into a mesh descriptor table with vertex_count, index_count, vertices, and indices fields.
use plugin gltf::{create_mesh}
let verts = [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.5, 1.0, 0.0]
let idx = [0, 1, 2]
let mesh = create_mesh(verts, idx)
print("vertices: {mesh["vertex_count"]}")The returned table keeps the flattened vertices and indices lists, so you can
read individual components back out by index:
use plugin gltf::{create_mesh}
let mesh = create_mesh([0.0, 1.0, 2.0], [0])
print("first vertex x/y/z: {mesh["vertices"][0]}, {mesh["vertices"][1]}, {mesh["vertices"][2]}")
print("index count: {mesh["index_count"]}")Build a PBR material descriptor
Creates a PBR material descriptor with base color RGBA (0.0–1.0) and metallic/roughness factors.
use plugin gltf::{create_material}
let mat = create_material("steel", 0.8, 0.8, 0.9, 1.0, 0.9, 0.2)
print(mat["name"])The factors are stored as metallic, roughness, and the four base_color_*
fields, which you can read back when emitting glTF material JSON:
use plugin gltf::{create_material}
let gold = create_material("gold", 1.0, 0.84, 0.0, 1.0, 1.0, 0.1)
print("metallic: {gold["metallic"]}, roughness: {gold["roughness"]}")
print("red channel: {gold["base_color_r"]}")Return a 4x4 identity matrix
Returns a 16-element table representing the 4x4 column-major identity matrix. Use as a starting point for composing transforms.
use plugin gltf::{transform_identity}
let m = transform_identity()
print(m[0])List JSON and BIN chunks inside a GLB file
Iterates the chunk list in a GLB binary (skipping the 12-byte header) and returns a table of chunks, each with type ("JSON" or "BIN"), offset, and length.
use plugin gltf::{parse_glb_chunks}
let chunks = parse_glb_chunks(file_bytes)
print(chunks[0]["type"])
print(chunks[0]["length"])Each chunk records the offset just past its 8-byte sub-header, so you can find the
embedded binary buffer by scanning for the "BIN" chunk:
use plugin gltf::{parse_glb_chunks}
let chunks = parse_glb_chunks(file_bytes)
for chunk in chunks {
if chunk["type"] == "BIN" {
print("binary payload starts at byte {chunk["offset"]}")
}
}Build a scene node with optional transform and mesh
Creates a glTF scene node table. Translation is [x, y, z], rotation is a quaternion [x, y, z, w], scale is [x, y, z]. Pass nil for fields you want to omit.
use plugin gltf::{create_node}
let node = create_node("Cube", [0.0, 1.0, 0.0], nil, [1.0, 1.0, 1.0], 0)
print(node["name"])Omitted fields simply do not appear on the table, so a bare node carries only its name:
use plugin gltf::{create_node}
let empty = create_node("Empty", nil, nil, nil, nil)
print(empty["name"])Build a scene descriptor from a name and node list
Wraps a name and a list of node references into a glTF scene descriptor table.
use plugin gltf::{create_node, create_scene}
let node = create_node("Box", nil, nil, nil, 0)
let scene = create_scene("Main", [node])
print(scene["name"])Build a glTF accessor descriptor
Builds a glTF accessor descriptor. component_type is a GL constant (e.g. 5126 for FLOAT), type_name is "VEC3" or "SCALAR", etc.
use plugin gltf::{create_accessor_info}
let acc = create_accessor_info(5126, "VEC3", 3, 0, 0)
print(acc["type"])Build a glTF bufferView descriptor
Builds a glTF bufferView descriptor pointing into a buffer at a given offset and length.
use plugin gltf::{create_buffer_view}
let bv = create_buffer_view(0, 0, 36, 12, 34962)
print(bv["byteLength"])Build a translation matrix
Returns a 4x4 column-major translation matrix for the given X, Y, Z offsets.
use plugin gltf::{transform_translate}
let m = transform_translate(0.0, 2.5, 0.0)
print(m[12])Build a scale matrix
Returns a 4x4 column-major scale matrix.
use plugin gltf::{transform_scale}
let m = transform_scale(2.0, 2.0, 2.0)
print(m[0])Build a Y-axis rotation matrix
Returns a 4x4 column-major rotation matrix around the Y axis. angle is in radians.
use plugin gltf::{transform_rotate_y}
let m = transform_rotate_y(3.14159)Multiply two 4x4 column-major matrices
Multiplies two 4x4 column-major matrices together. Use to compose translation, rotation, and scale into a single transform.
use plugin gltf::{transform_translate, transform_rotate_y, multiply_transforms}
let t = transform_translate(1.0, 0.0, 0.0)
let r = transform_rotate_y(1.5708)
let combined = multiply_transforms(t, r)Because the result is itself a 4x4 matrix table, calls chain to build a full transform stack:
use plugin gltf::{transform_identity, transform_scale, transform_translate, multiply_transforms}
let m = multiply_transforms(transform_identity(), transform_scale(2.0, 2.0, 2.0))
let placed = multiply_transforms(transform_translate(0.0, 5.0, 0.0), m)
print("scaled and lifted: y offset is {placed[13]}")