@needle-tools/addressing
v0.3.3
Published
Persistent addressing for Needle assets: deterministic needle-id computation, #needle anchors, and address resolution over glTF JSON and live scene graphs.
Readme
@needle-tools/addressing
Persistent addressing for glTF assets and three.js scene graphs: deterministic
needle-id computation, the #needle name-anchor scheme, and address resolution.
Zero runtime dependencies, no three.js import (scene graphs are accessed structurally), usable in browsers, node, and workers.
Ids
Every glTF root-collection element (nodes, scenes, animations, cameras, materials,
meshes, skins, textures, images, samplers) can carry a UUID in extras["needle-id"]:
- Anchored — the element name ends with
#needle(case-insensitive): the id derives only from the text before the marker → it survives any content change as long as the name stays. Spaces and underscores in the value are treated as equal (loaders sanitize node names), soDoor Frame #needleandDoor_Frame_#needleshare one id. - Unanchored: the id derives from the element's type, name, and its occurrence among same-named elements → uniquely named elements keep their ids across reorders and content updates; duplicates disambiguate by position within their name group; unnamed elements are positional.
ensureIds(gltfJson) stamps a parsed glTF idempotently — existing ids are never
overwritten, and any tool stamping the same element mints the same id.
ensureIds(gltfJson, { baseHash }) optionally salts unanchored ids with a caller-supplied
identity (e.g. a stable asset id), scoping them to that identity.
Addresses
An address captures every fallback at creation time, while the target is known —
{ id, anchor?, type?, name?, namePath? }. Resolution order is strict:
id— exact match (extrasin glTF JSON,userDatain live scene graphs)anchor— survives asset updatesnamePath— best-effort structural match- reconciliation — never automatic:
reconcileInGraphreturns ranked candidates with confidence + reasons; the caller decides thresholds and whether to re-anchor.
API
import {
ensureIds, computeElementId, computeFileHash, // write side
createGltfElementAddress, createObjectAddress, // address records
resolveInGltf, resolveInGraph, reconcileInGraph, // resolve side
parseAnchorValue, randomUuid, NEEDLE_ID_KEY,
} from "@needle-tools/addressing";
// stamp a parsed glTF (idempotent, never overwrites existing ids)
const { fileHash, assigned } = ensureIds(gltfJson);
// capture an address while the target is known
const address = createObjectAddress(sceneRoot, targetObject);
// later / elsewhere: resolve — or reconcile when the asset changed
const hit = resolveInGraph(address, sceneRoot);
const candidates = hit ? [] : reconcileInGraph(address, sceneRoot);Out of scope by design: GLB container parsing (this package takes parsed JSON), file I/O, and any composition/override semantics.
Development
npm install
npm test # vitest — includes golden-fixture id tests
npm run build # tsc → dist/