RFD 1061 details: what idtx_core carries, the path there, the stopgap, a bug
thirdparty/fabric-stage-runtime/ and thirdparty/fabric-flow-adapters/ are vendored as git subtrees, at main and main-fabric respectively.
What idtx_core carries that browser compression does not
thirdparty/fabric-flow-adapters/flow/ already carries three things this repository’s browser compression lacks.
- Content-defined chunking, casync-compatible, SHA-512/256 chunk IDs (
idtx_chunker.h). Two uploads of the same mesh, or two revisions that share most of their geometry, share most of their chunks. Nothing here gets resent. - USD-native mesh and VRM handling (
idtx_import_usd.cpp,idtx_export_usd.cpp,idtx_vrm.cpp), which composes with RFD 1053’s decision to make OpenUSD the internal format instead of round-tripping GLB at every stage. - AES + zstd transport (
idtx_aes.cpp,idtx_transport.cpp) already built for exactly this shape of problem. The same chunker/transport pair backsmultiplayer-fabric-godot’s asset streaming.
Why none of this is reachable yet
flow/adapters/ holds three hosts: godot/ (GDExtension), unity/ (P/Invoke), and cli/. It holds no fourth. Getting there needs:
- An Elixir NIF (or Rustler-style binding) linking
idtx_corethrough the ports it already exposes (flow/ports/include/idtx_core/), built against the OpenUSDfabric-stage-runtimealready ships as{:stage_runtime, "~> 0.1.0-dev"}. RFD 1053 already commitsweftspun_studioto linking that build. - A
weftspun_studioAPI route the browser uploads to, instead of whateverimage_to_textured_mesh-style route it POSTs a GLB to today. - The browser call site swapped from
compressGlbBuffer/prepareGlbForApiUploadto that route.
This RFD records the target and stops there. Building the NIF, the port, the adapter, and the route is its own multi-session scope. It is RFD 1057-style open work, not a task this RFD’s Decision closes.
The interim stopgap, in glbCompress.js today
This stopgap works in GLB, against RFD 1053’s own rule that GLB stays a transmission format and never the working format. It exists only to unblock the failing test and the throwing import, until the NIF adapter lets this path move to USD-native handling instead.
Two functions now exist, so the test the gap left red passes and TaskManager.jsx’s import resolves.
computeApiUploadSimplifyRatio(sourceVerts, sourceFaces, maxVertices, maxFaces, headroom = 0.85) gives the fraction of the current mesh to keep, driven by whichever cap (verts or faces) needs the deeper cut. It returns 1 when both are already under cap.
prepareGlbForApiUpload(arrayBuffer, { maxVertices, maxFaces }) passes a buffer through unchanged when it fits. Otherwise it welds, then loops simplify plus dedup plus prune, up to 5 passes. Each pass re-measures against the cap, since simplify’s ratio is relative to the current triangle count and not the source. It throws if a rigged mesh (joints, weights, or morph targets, per documentNeedsSafeMode) stays over the cap, since decimation skips a rig to protect it. TaskManager.jsx’s call site relies on that throw to drive its “too dense to auto-rig” warning.
Both are gltf-transform over the same getIO() pipeline compressGlbBuffer already uses in this file. Nothing here is a step toward the idtx_core path. Replace this whole block, and do not extend it, once the NIF adapter exists.