ConstReadonlypoint: { glsl: () => typeof PointMaterial; tsl: () => typeof PointTSLMaterial }Readonlyline: { glsl: () => typeof LineMaterial; tsl: () => typeof LineTSLMaterial }Readonlygsplat: { glsl: () => typeof GSplatMaterial; tsl: () => typeof GSplatTSLMaterial }Readonlymesh: { glsl: () => typeof MeshMaterial; tsl: () => typeof MeshTSLMaterial }ReadonlymeshPhysical: {The mesh's second material FAMILY, not a fifth geometry type: three's own
physically based material behind the Luxar leaf surface
(MESH_PHYSICAL_MATERIALS_SPEC.md §3.2). A separate key rather than a variant of
mesh because none of the house contracts apply to it — no codegen snapshot, no
per-epoch shading define, no blend-mode state — and, deliberately, NO matching
PICKING_FACTORIES entry: picking renders geometry, not appearance, so a physical
mesh picks through the house mesh pick material.
Constructor table for the visual material pair of each geometry type.
MaterialManager.get{Point,Line,GSplat,Mesh}Materiallooks upVISUAL_FACTORIES[kind][backend]()to pick the class to instantiate.Every cell is a thunk rather than the class itself. The
glslones do not need to be, but keeping both backends the same shape is what lets the call sites stay a uniform[backend]()lookup — and thetslones must be, because their classes live behind the lazythree/webgpuboundary (rendering/tsl/load.ts) and do not exist until it has been awaited. A thunk that resolves late is also why the laziness is visible at the point of use instead of hiding in a getter that throws when a debugger inspects it.