-
2026-07-17 — USD support, zero-dep:
file_utils/usd.py(UsdFile/UsdzPackager/UsdMeshWriter+obj_to_usd/obj_to_usdz). Pure-Python USD primitives with nopxrdependency, per the package charter: format sniffing by magic bytes (#usda/PXR-USDC/zip — content wins over extension), a spec-compliant.usdzwriter/verifier over stdlibzipfile(stored entries, 64-byte-aligned data offsets via zero-padded extra fields, default layer first —UsdzPackager.verifyreads data offsets back from the local headers),UsdzPackager.from_layer(self-contained package from a text layer: on-disk texture refs pulled in undertextures/and rewritten; composed by mayatk's.usdzexport), and a.usdamesh author + minimal OBJ/MTL reader — the no-DCC publish path (photogrammetry: Metashape OBJ in, QuickLook-ready USDZ out, no license). Cross-validated against the real USD runtime twice over: the optionalusd-corewheel opens the authored layers/packages intest_usd.py, and Blender's importer + bundledpxraccept them in blendertk's suite. DCC-native USD I/O builds on this downstream (mayatk/blendertkenv_utils/usd.py). -
2026-07-17 — Package-structure review: no relocations warranted;
core_utils' flat layout documented as deliberate (no code change to the tree). An architectural pass over the package tree confirmed the existing layout is sound and holds a convention worth stating: a root<name>_utils/subpackage earns its place with either a_<name>_utils.pyfacade (StrUtils,MathUtils,FileUtils, … — 9 of the 10 leaf packages) or a multi-module primitive family (geo_utils—Polyline/PointCloud/RailSurface, the lone justified facade-less package). A first cut of this review had splitColorinto a newcolor_utils/and the mesh tools into a newmesh_utils/; both were reverted — each is a lone module that clears neither bar, and wrapping a single module in a package (or inventing aColorUtils/MeshUtilsfacade to justify one) is nesting-for-cosmetics, the same YAGNI wrapperCLAUDE.mdwarns off.Color/ColorPair/Palettestay incore_utils/color.py(a homeless shared primitive lodged beside the other cross-cutting code — the precedent isMetadataliving infile_utils);MeshConvert/MeshCleanerstay infile_utils(mesh files are files, andMeshCleanermanipulates topology, whichgeo_utils' charter explicitly disclaims). What did land:core_utils/__init__now documents its cluster taxonomy (class infrastructure / app-process orchestration / config & persistence / package-dev infra / pipeline primitives / data structures / the homelesscolorprimitive / engines) and why it stays flat — its module paths are cross-package import contracts (module_resolver×20 downstream sites,app_launcher×15,logging_mixin×11, …), so re-nesting would be ~70 import edits across five packages for zero functional gain. Also fixedcreate_namespace_aliases' docstring example: it referenced the long-gonecore_utils.auto_instancermodule (broken since that engine's relocation) and its trailingpkg.Instancing()line didn't match the alias it set up. Rather than repoint it at another concrete module — value types likecolorcan't even be fused (multiple-inheritance layout conflict), and any real reference rots when modules move — it's now an abstract, drift-proofFooMixin/BarMixinexample that also documents the co-inheritability constraint the previous forms silently violated. (The standalonecreate_namespace_aliasesfunction has no callers ecosystem-wide — packages declare aliases via the resolver'snamespace_aliasesmap — so this is doc-only.) Public root API unchanged throughout; full suite green (1919 tests, 0 failures, 17 skipped).