Skip to content

Instantly share code, notes, and snippets.


Don McCurdy donmccurdy

View GitHub Profile
donmccurdy / gen-torus.js
Last active August 19, 2023 13:54
Sample code for generating a torus-shaped GLB from scratch using glTF Transform.
View gen-torus.js
import { Document, NodeIO } from '@gltf-transform/core';
function createTorus(radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2) {
const indicesArray = [];
const positionArray = [];
const texcoordArray = [];
const vertex = [0, 0, 0];
// generate positions and uvs
donmccurdy /
Created January 31, 2023 02:35
Example script for batch CLI processing with glTF Transform.
for file in $FILES; do
echo "Compressing $file..."
gltf-transform draco "${file%.glb}.glb" "${file%.glb}-draco.glb"
donmccurdy / EXTRACT_GEOMETRY.mjs
Last active September 27, 2022 04:22
Example Node.js script using glTF-Transform to extract geometry from a glTF document and create a geometry-only three.js scene graph.
import { NodeIO } from '@gltf-transform/core';
import { KHRONOS_EXTENSIONS } from '@gltf-transform/extensions';
import draco3d from 'draco3dgltf';
// set up I/O
const io = new NodeIO()
.registerDependencies({'draco3d.decoder': await draco3d.createDecoderModule()});
const document = await'path/to/file.glb');
donmccurdy / generate_lods.mjs
Last active August 15, 2023 04:15
Example implementation of MSFT_lod in glTF-Transform.
View generate_lods.mjs
import { Extension, ExtensionProperty, Node, NodeIO, PropertyType } from '@gltf-transform/core';
import { weld, dedup, simplifyPrimitive } from '@gltf-transform/functions';
import { MeshoptSimplifier } from 'meshoptimizer';
* Example implementation of MSFT_lod for glTF-Transform.
* ⚠️ NOTICE: This code is provided for the sake of example, and is not tested or
* maintained. For a full implementation, refer to:
donmccurdy /
Created July 10, 2022 23:23 — forked from sindresorhus/
Pure ESM package

Pure ESM package

The package linked to from here is now pure ESM. It cannot be require()'d from CommonJS.

This means you have the following choices:

  1. Use ESM yourself. (preferred)
    Use import foo from 'foo' instead of const foo = require('foo') to import the package. You also need to put "type": "module" in your package.json and more. Follow the below guide.
  2. If the package is used in an async context, you could use await import(…) from CommonJS instead of require(…).
  3. Stay on the existing version of the package until you can move to ESM.
donmccurdy /
Last active May 5, 2022 16:08
Initialization order and public class properties
donmccurdy / bin-plugin.js
Last active December 29, 2022 17:06
Example vite/rollup plugin for processing binary files.
View bin-plugin.js
import { createFilter, normalizePath } from "@rollup/pluginutils";
import fs from "fs/promises";
import crypto from "crypto";
import path from "path";
const PLUGIN_NAME = "bin";
const HASH_LENGTH = 8;
donmccurdy / create-basic-glb.js
Created February 27, 2022 21:59
Create a basic GLB with a single mesh.
View create-basic-glb.js
import { Accessor, Document, Primitive, NodeIO } from '@gltf-transform/core';
const document = new Document();
const prim = document.createPrimitive();
const buffer = document.createBuffer();
const material = document.createMaterial()
.setBaseColorFactor([1.0, 0.0, 0.0, 1.0])
donmccurdy / flat-normals.ts
Last active February 12, 2022 17:22
Compute flat normals in glTF-Transform
View flat-normals.ts
import { vec3 } from 'gl-matrix';
import { unweld } from '@gltf-transform/functions';
await document.transform(unweld());
for (const mesh of document.getRoot().listMeshes()) {
for (const prim of mesh.listPrimitives()) {
const position = prim.getAttribute('POSITION');
const normal = document.createAccessor()
.setArray(new Float32Array(position.getCount() * 3))
donmccurdy /
Last active July 27, 2023 15:48
Divide glTF Document

Divide glTF Document

Example script showing how to use glTF-Transform ( to divide a glTF asset — along an axis — into two GLBs, each occupying half the original bounding box. This is just a rough illustration, and has only been tested against a point cloud containing a single mesh. A production implementation would want to do more than this:

  • support >2 divisions
  • for primitives that lie fully in one division, don't write an empty primitive to the others
  • support triangles, lines, etc.

For input with significant outliers (e.g. noisy point clouds), dividing by the center of the bounding box may give unexpected results.