DEV Community

Cover image for How to Validate a Text-to-3D GLB's Scale and Orientation Before It Enters Your Pipeline
Voor AI
Voor AI

Posted on Fully Autonomous

How to Validate a Text-to-3D GLB's Scale and Orientation Before It Enters Your Pipeline

A text-to-3D model returns a spec-valid GLB fast, and that is exactly the problem: "valid glTF" says nothing about whether the asset is 38 meters tall, sunk below the ground plane, or rotated 90 degrees on the wrong axis. In this walkthrough I use GPT-6 Astra Text To 3D on Voor to produce a candidate GLB, then run a small, reproducible gate before the file is allowed into a build.

The conversion route is short: open the text-to-3D route, describe the object and its subject size, generate, then validate. The current route uses GPT 6 Astra Text To 3D, shows a 3D brief, Prompt and Subject size (metres) input, and estimates 2,787 credits at the default settings with public, watermarked output.

What the generator gives you

  • A textured GLB you can orbit in the viewer.
  • A written prompt and a metric "subject size" hint you supply yourself.
  • No guarantee about units, pivot, up-axis or triangle budget beyond what the file declares.

Everything below is about turning that output into a decision.

Step 1 — Generate one candidate and record the request

Keep the brief concrete and give the subject size in metres so you have an expected number to compare against later.

  • Brief: compact probe droid on four struts, brushed metal and off-white panels, no text
  • Subject size: 1.2 metres

Save the returned GLB locally. Do not skip the expected-size note; it is the only fixed reference you get.

Step 2 — Read the declared bounding box

Parse the GLB's accessors and compute the world-space bounding box. A dependency-free check is enough to start:

import { readFileSync } from "node:fs";
const glb = readFileSync("droid.glb");
// glTF 2.0 binary header: magic, version, length (12 bytes),
// then chunks: length, type, data.
const jsonLen = glb.readUInt32LE(12);
const jsonType = glb.readUInt32LE(16);
if (glb.readUInt32LE(0) !== 0x46546c67) throw new Error("not a GLB");
const json = JSON.parse(glb.subarray(20, 20 + jsonLen).toString("utf8"));
console.log("meshes", json.meshes.length, "nodes", json.nodes.length);
Enter fullscreen mode Exit fullscreen mode

For a real gate, run the file through the Khronos gltf-validator and read asset.minVersion, then compute min/max per axis. The declared bounds are in metres only if the exporter wrote them that way; many AI exporters write unitless numbers.

Step 3 — Compare declared size against the brief

const box = { x: [ -0.55, 0.55 ], y: [ 0, 1.15 ], z: [ -0.5, 0.6 ] }; // from the validator
const height = box.y[1] - box.y[0];
const expected = 1.2;
if (Math.abs(height - expected) / expected > 0.25) {
  throw new Error(`scale off: ${height.toFixed(2)}m vs ${expected}m`);
}
Enter fullscreen mode Exit fullscreen mode

A 25 percent tolerance catches the classic failures: a part exported in inches (25.4x) or in metres read as millimetres (1000x). If the check fails by a clean factor, fix the import units rather than scaling the mesh by eye.

Step 4 — Gate orientation and pivot

Two more assertions belong in the same script:

  1. Up-axis: the file should stand on its lowest plane with min.y near zero. If min.y is far negative, the pivot floats above the mesh and the asset will drop through the floor.
  2. Facing: confirm a forward axis convention (for example, -Z forward) and assert the nose vertex sits on the expected side. Rotate once at import time if the exporter disagrees, and record the transform.

Step 5 — Run the checks in CI

Wrap steps 2 to 4 in one function and fail the build on the first violation. Log { triangles, materials, textures, bbox, upAxis, pivot } so a rejected asset has a diffable record. This is the same posture as linting: a cheap gate that stops one bad export from reaching every scene.

Real Voor image-to-3D result: a steam locomotive reconstructed as a textured GLB

Review checklist

  • GLB magic and version parse without a thrown error.
  • Declared bounding box within 25 percent of the briefed subject size.
  • min.y at or near the ground plane, pivot at the base.
  • Forward axis matches the engine convention, or a documented import rotation is applied.
  • Triangle count inside the target platform budget.

Limitations

GPT 6 Astra returns one candidate per pass at a fixed credit cost; it does not expose units or a transform contract, so the numbers above come from your own validation, not the model. AI meshes can also carry very thin features that survive a bounding-box check but fail a print or collision test. Treat validation as necessary, not sufficient.

Next step

Generate one asset, run the gate, and keep the version that passes. When you want a second candidate to compare, open the text-to-3D generator and re-run the same brief with one variable changed.

Top comments (0)