export type BoxelId = string;
export type PatternId = string;
export type MaterialId = string;
export type TextureId = string;
export type PrimitiveId = string;
export type NodeId = string;
export type GeometryId = string;
export type AnimationId = string;
export type Vec2 = [number, number];
export type Vec3 = [number, number, number];
export type PrimitiveKind = 'plain_box' | 'textured_box' | 'voxel_box' | 'combo_box';
export type ConnectMode = 'none' | 'child' | 'parent' | 'both';
export interface Node {
    id: NodeId;
    position: Vec3;
    /**
     * Applied in XYZ order (likely radians) if provided; omitted means default rotation.
     */
    rotation?: Vec3 | undefined;
    /**
     * Uniform axes scaling override; defaults to [1,1,1] when omitted.
     */
    scale?: Vec3 | undefined;
    /**
     * Bounding size for the attached primitive instance; required for combo imports and voxel authoring.
     */
    size?: Vec3 | undefined;
    /**
     * Local-space offset applied to the primitive mesh within this node. Keeps the node pivot in place
     * while sliding geometry (e.g. aligning a foot pivot); defaults to [0,0,0].
     */
    center?: Vec3 | undefined;
    /**
     * Controls how this node blends with its parent when building a skinned mesh.
     * - 'none' (default): no welding; the node remains fully bound to its own bone.
     * - 'child': child vertices overlapping the parent bounds blend into the parent bone.
     * - 'parent': parent vertices overlapping this node's bounds blend into the child bone.
     * - 'both': mirror welding on both parent and child geometry.
     * A legacy boolean `true` maps to 'child'.
     */
    connect?: ConnectMode | undefined;
    /**
     * Primitive bound to this node. When undefined, the node acts as a pure transform/group.
     */
    mesh?: PrimitiveId | undefined;
    children: Node[];
}
export interface Geometry {
    id: GeometryId;
    root: Node;
}
export interface Material {
    id: MaterialId;
    baseColor: Vec3;
    emissiveColor?: Vec3 | undefined;
    opacity?: number | undefined;
}
export interface Pattern {
    id: PatternId;
    size: Vec2;
    data: number[];
}
export interface Texture {
    id: TextureId;
    pattern: PatternId;
    materials: MaterialId[];
}
interface BoxPrimitiveBase {
    id: PrimitiveId;
    kind: PrimitiveKind;
    size: Vec3;
}
export interface PlainBox extends BoxPrimitiveBase {
    kind: 'plain_box';
    material: MaterialId;
}
export interface TexturedBox extends BoxPrimitiveBase {
    kind: 'textured_box';
    top?: TextureId | undefined;
    bottom?: TextureId | undefined;
    north?: TextureId | undefined;
    south?: TextureId | undefined;
    east?: TextureId | undefined;
    west?: TextureId | undefined;
    /**
     * Texture applied to all four side faces (north, south, east, west) when an individual face texture
     * is not specified. Individual face properties still win when present.
     */
    sides?: TextureId | undefined;
    /**
     * Texture applied as a catch-all fallback for every face when no face-specific or `sides` texture
     * is provided. Evaluated last after top/bottom/sides.
     */
    all?: TextureId | undefined;
    /**
     * Rendering mode for the primitive.
     * - `plain`: opaque surface; faces are single sided and rendered without alpha cutouts.
     * - `cutout`: semi-transparent/cutout surface; faces render double sided with alpha testing.
     */
    renderMode?: 'plain' | 'cutout' | undefined;
    /**
     * Optional overlay textures rendered as a thin outer shell using cutout blending. Overlay fields
     * follow the same fallback rules as their base counterparts (face > sides > all).
     */
    topOverlay?: TextureId | undefined;
    bottomOverlay?: TextureId | undefined;
    northOverlay?: TextureId | undefined;
    southOverlay?: TextureId | undefined;
    eastOverlay?: TextureId | undefined;
    westOverlay?: TextureId | undefined;
    sidesOverlay?: TextureId | undefined;
    allOverlay?: TextureId | undefined;
}
export interface VoxelBox extends BoxPrimitiveBase {
    kind: 'voxel_box';
    /**
     * Flattened material indices for the voxel volume. Length must equal size[0] * size[1] * size[2].
     * Index ordering is X-major, then Y, then Z (x + y * sizeX + z * sizeX * sizeY). A value of 0
     * denotes empty space, while positive values reference palette entries (value - 1).
     */
    voxels: number[];
    /**
     * Materials available to this voxel primitive. Voxels value of N > 0 resolves to palette[N - 1],
     * so palette[0] is the material used when voxels contains 1.
     */
    palette: MaterialId[];
}
export interface ComboBox extends BoxPrimitiveBase {
    kind: 'combo_box';
    slots: Array<{
        id: string;
        primitive: PrimitiveId;
        offset: Vec3;
    }>;
}
export type Primitive = PlainBox | TexturedBox | VoxelBox | ComboBox;
export type AnimationChannelProperty = 'position' | 'rotation' | 'scale';
export interface AnimationKeyframe {
    time: number;
    value: Vec3;
}
export interface AnimationChannel {
    node: NodeId;
    property: AnimationChannelProperty;
    keyframes: AnimationKeyframe[];
}
export interface Animation {
    id: AnimationId;
    /**
     * Total clip length in seconds. Keyframe times are expected to fall within [0, duration].
     */
    duration: number;
    channels: AnimationChannel[];
}
export interface BoxelDefinition {
    /**
     * Stable entity identifier persisted with serialized definitions so tooling can reference entities
     * without relying on filenames.
     */
    id: BoxelId;
    geometry: Geometry;
    patterns: Pattern[];
    materials: Material[];
    textures: Texture[];
    primitives: Primitive[];
    animations: Animation[];
}
export {};
