import { NodeIO, type Document } from '@gltf-transform/core'; import type { Bounds, CompiledSceneArtifact } from './types'; /** * Collision-proxy derivation shared by every intake format. * * Lives apart from the FBX compiler so OBJ/GLB-only packs never load the * ESM-only three.js loaders this repo cannot import under Jest: proxies are * pure glTF-Transform work — flat default material, meshopt simplification, * prune — independent of where the detail GLB came from. */ export declare function artifactFromDocument(io: NodeIO, document: Document, filename: string, bounds: Bounds): Promise; /** * A proxy costs a whole resource FILE out of the build endpoint's 199-file * budget, so a proxy is only worth emitting when it is meaningfully smaller * than the detail it stands in for. Measured over the QA packs and the Pacifica * mall corpus, a proxy either lands at <= 27% of detail triangles (the welded * route hits its target exactly) or at 100% (meshopt floored on attribute * seams) — there is no observed middle ground, so a 70% gate separates the two * populations with room to spare rather than sitting on top of either. */ export declare const PROXY_KEEP_MAX_TRIANGLE_RATIO = 0.7; /** * Below this, the DETAIL mesh already is the cheap level: a 30-triangle, * 3.8 KB prop cannot pay back the file slot, the extra fetch, and the LOD pop * its proxy would cost. Both floors must be undershot — a small-triangle mesh * carrying a big texture payload still benefits from a geometry-only proxy. */ export declare const PROXY_MIN_DETAIL_TRIANGLES = 512; export declare const PROXY_MIN_DETAIL_BYTES: number; /** * How far the attribute-preserving pass may miss its triangle target before the * seam-breaking fallback is attempted. * * The first cut of this gate asked the WRONG QUESTION. It fired the fallback on * `triangles > detail * PROXY_KEEP_MAX_TRIANGLE_RATIO` — a RELATIVE test against * the keep gate — so a mesh that reduced to 66.9% of its source slipped under * 0.7 and the fallback was never attempted, even though it had missed its own * target by 13x. The Pacifica mall's SM_Generator is exactly that shape: 67,139 * triangles against a 3,403 target, floored at 44,929 by attribute seams and * accepted as a success. Routed through the fallback it reaches 3,398. * * A miss is measured against the TARGET, because that is what the caller asked * for. The tolerance keeps the expensive pass off meshes that essentially landed * (a 3,500-triangle result against a 3,403 target is not seam-blocked); anything * beyond half again its target is presumed stuck and worth a second attempt. */ export declare const PROXY_TARGET_MISS_TOLERANCE = 1.5; /** Why a proxy was kept, or the named reason it was not. */ export type ProxyDecision = 'kept' | 'below-complexity-floor' | 'no-triangle-reduction' | 'not-smaller-in-bytes'; /** The before/after `simplifiedProxyArtifact` used to discard. */ export type ProxyReduction = { name: string; detailTriangles: number; detailPrimitives: number; detailBytes: number; /** The triangle target this mesh was simplified toward; null below the floor. */ targetTriangles: number | null; proxyTriangles: number | null; proxyPrimitives: number | null; proxyBytes: number | null; /** proxy triangles / detail triangles; null when no proxy was produced at all. */ triangleRatio: number | null; byteRatio: number | null; /** Which simplification route produced the measured proxy. */ strategy: 'none' | 'attribute-preserving' | 'position-welded'; kept: boolean; decision: ProxyDecision; }; export type ProxyOutcome = { /** null when no proxy earned its file slot — the caller must emit a single-level LOD. */ proxy: CompiledSceneArtifact | null; reduction: ProxyReduction; }; /** * Should the seam-breaking fallback be attempted after the attribute-preserving * pass returned `candidateTriangles`? * * Kept as a pure predicate because the ORIGINAL BUG WAS IN THIS DECISION, not in * either simplification route: asking only whether the candidate sat above the * keep ratio let a mesh that missed its target 13-fold count as a success. Both * questions have to be asked — did it reach what the caller asked for, and did it * move at all relative to the source. */ export declare function shouldAttemptWeldedFallback(input: { candidateTriangles: number; detailTriangles: number; targetTriangles: number; }): boolean; /** * Derives the collision proxy from one compiled detail artifact: flat default * material, meshopt-simplified, pruned — and then MEASURED against the detail * it replaces. A proxy that did not actually get smaller is not emitted; the * caller declares a single-level LOD for that mesh instead, because one real * level beats two identical ones and costs half the file budget. */ export declare function simplifiedProxyArtifact(io: NodeIO, detail: CompiledSceneArtifact, name: string, targetTriangles?: number): Promise; /** One-line compile summary over every mesh's proxy decision. */ export declare function summarizeProxyReductions(reductions: readonly ProxyReduction[]): string; /** Loud, per-NAMED-mesh warnings for every proxy that missed the reduction target. */ export declare function proxyReductionWarnings(reductions: readonly ProxyReduction[]): string[];