/**
* VAV (Vertex Animation Video) plane codec: the pure product quantization layer between
* baked per-frame vertex data and canonical byte planes.
*
* The runtime consumes this plane layout from exact UTSBM blocks:
* - GEOMETRY: 16-bit position hi/lo ×3 against clip-global bounds, plus the 8-bit
* octahedral-normal pair when present. A changed high byte can move a vertex across the
* bounding box, so exactness is checked at these post-quantization integers.
* - APPEARANCE: named 8-bit scalar planes — `ao`, `red`/`green`/`blue`,
* `R/G/B` triplets, or arbitrary baked per-vertex data. Names are free-form (see
* {@link VAV_PLANE_NAME_PATTERN}); the runtime exposes each plane as a TSL node by name.
*
* Unlike correspondence-free splats, vertex order is fixed across frames, so each plane lane
* has stable temporal correspondence in the persisted lanes.
*
* Spec: `docs/formats/vav-manifest.md`; layout constants here are the implementation
* source of truth.
*
* @module VAVFrames
*/
/** The fixed position planes that start every GEOMETRY track (top to bottom). */
export declare const VAV_POSITION_PLANES: readonly ["posXHi", "posXLo", "posYHi", "posYLo", "posZHi", "posZLo"];
/** The octahedral normal pair — appended to the GEOMETRY track when the bake has normals. */
export declare const VAV_NORMAL_PLANES: readonly ["normalOctU", "normalOctV"];
/**
* Valid APPEARANCE plane names: identifier-like so they can double as TSL varying names.
* Conventions the runtime sugars: `ao` (aoNode), `red`/`green`/`blue` (colorNode), and
* `R`/`G`/`B` triplets (a vec3 node per base).
*/
export declare const VAV_PLANE_NAME_PATTERN: RegExp;
/** Appearance plane count cap — keeps the atlas within sane texture dimensions. */
export declare const VAV_MAX_APPEARANCE_PLANES = 32;
/** Three-component clip-global position bounds. */
export type VAVVec3 = readonly [number, number, number];
/** Atlas dimensions shared by the CPU encoder and GPU decoder. */
export interface VAVAtlasLayout {
width: number;
rowsPerPlane: number;
geometryHeight: number;
appearanceHeight: number;
}
/** Ordered plane names for the exact geometry and appearance tracks. */
export interface VAVPlaneSets {
geometry: readonly string[];
appearance: readonly string[];
}
/** One baked frame before plane quantization. */
export interface VAVFrame {
positions: Float32Array;
normals?: Float32Array;
channels?: Readonly>;
}
/** Clip-global dequantization ranges. */
export interface VAVRanges {
bounds: {
min: VAVVec3;
max: VAVVec3;
};
channels?: Readonly>;
}
/** Quantized luma plane stacks for one frame. */
export interface VAVEncodedFramePlanes {
geometry: Uint8Array;
appearance: Uint8Array | null;
}
/** Vertex attributes reconstructed from one pair of plane stacks. */
export interface VAVDecodedFrame {
positions: Float32Array;
normals: Float32Array | null;
channels: Record | null;
}
/**
* Atlas layout for `vertexCount` vertices: vertex i lives at texel (i % width, plane·rows +
* floor(i / width)). Width and stack heights are kept even (codec requirement).
*
* @param {number} vertexCount - Unique vertex count (indexed geometry).
* @param {number} [width=1024] - Atlas width in texels.
* @param {string[]} [geometryPlanes=VAV_POSITION_PLANES] - Ordered geometry plane names (6 position planes, optionally + the oct normal pair).
* @param {string[]} [appearancePlanes=[]] - Ordered appearance plane names.
* @returns {{ width:number, rowsPerPlane:number, geometryHeight:number, appearanceHeight:number }}
*/
export declare function vavAtlasLayout(vertexCount: number, width?: number, geometryPlanes?: readonly string[], appearancePlanes?: readonly string[]): VAVAtlasLayout;
/**
* Encode a unit normal into two 8-bit octahedral bytes (worst-case ~0.5° at 8 bits).
*
* @param {number} x
* @param {number} y
* @param {number} z
* @returns {[number, number]} `[u, v]` bytes in 0..255.
*/
export declare function octEncodeNormal(x: number, y: number, z: number): [number, number];
/**
* Decode two octahedral bytes back into a unit normal (the CPU twin of the TSL decoder in
* {@link module:VAVNodes}).
*
* @param {number} u - Byte 0..255.
* @param {number} v - Byte 0..255.
* @param {Float32Array} out - Destination array.
* @param {number} [offset=0] - Write offset (xyz).
*/
export declare function octDecodeNormal(u: number, v: number, out: Float32Array, offset?: number): void;
/**
* Quantize one frame into the two mono plane stacks (geometry, appearance) as flat
* `Uint8Array`s of `width × height` luma bytes. Texels beyond `vertexCount` replicate each
* plane's last real value; the decoder never samples those padding texels.
*
* @param {Object} frame - `{ positions:Float32Array(3V), normals?:Float32Array(3V), channels?:Object. }` — one scalar array (V values, linear) per appearance plane name.
* @param {Object} layout - From {@link vavAtlasLayout}.
* @param {Object} ranges - `{ bounds: { min:[x,y,z], max:[x,y,z] }, channels?:Object. }` (clip-global; `channels` holds each appearance plane's fixed linear headroom, default 1 — HDR planes like a direct+indirect GI bake need it).
* @param {{ geometry:string[], appearance:string[] }} planes - Ordered plane names per track.
* @param {number} vertexCount - Vertices per frame.
* @returns {{ geometry:Uint8Array, appearance:Uint8Array|null }}
*/
export declare function encodeVAVFramePlanes(frame: VAVFrame, layout: VAVAtlasLayout, ranges: VAVRanges, planes: VAVPlaneSets, vertexCount: number): VAVEncodedFramePlanes;
/**
* Decode one frame's vertex arrays from the two luma plane stacks (the exact inverse of
* {@link encodeVAVFramePlanes} up to quantization). The CPU
* twin of the GPU sampling path — used by the encoder's round-trip gate and the tests.
*
* @param {Uint8Array} geometry - Geometry-track luma bytes (width × geometryHeight).
* @param {Uint8Array|null} appearance - Appearance-track luma bytes (or null).
* @param {Object} layout - From {@link vavAtlasLayout}.
* @param {Object} ranges - Same ranges the encoder used.
* @param {{ geometry:string[], appearance:string[] }} planes - Ordered plane names per track.
* @param {number} vertexCount - Vertices per frame.
* @returns {{ positions:Float32Array, normals:Float32Array|null, channels:Object.|null }}
*/
export declare function decodeVAVFramePlanes(geometry: Uint8Array, appearance: Uint8Array | null, layout: VAVAtlasLayout, ranges: VAVRanges, planes: VAVPlaneSets, vertexCount: number): VAVDecodedFrame;
/**
* Frame timestamp in microseconds — the ONE formula both the encoder (embedded `.af`
* manifests) and the runtime (chunks fed to `VideoDecoder`) must use, so decoded-frame
* timestamps map back to frame indices exactly.
*
* @param {number} index - Frame index.
* @param {number} frameRate - Clip frame rate.
* @returns {number} Timestamp in µs.
*/
export declare function vavFrameTimestamp(index: number, frameRate: number): number;