Repository navigation
logic export
Pure logic mapping the groups under the track parent group into Create/Kuayue model file names and generating the matching blockstates JSON. Zero dependencies, Node-testable.
Export modes (see EXPORT_MODES): new_java (1.21.11+, format_version, multi-axis {x,y,z}),
classic_java (1.21.11-, no format_version, single-axis only), bedrock (minecraft:geometry), obj
(single merged OBJ mesh). Elements that can't be exported fall back to OBJ (see groupNeedsObj).
export type ExportMode = 'new_java' | 'classic_java' | 'bedrock' | 'obj';
// id / label / eligibility description (label + description are i18n-localized)
export const EXPORT_MODES: { id: ExportMode; label: string; description: string }[];Extracted by the Blockbench layer from live Cubes/Meshes and handed to the pure functions. Face textures
use a stable textureKey (the Blockbench layer maps Texture instances to 't0'/'t1'…).
export interface ExportFaceData {
uv?: [number, number, number, number];
rotation?: number;
textureKey?: string;
}
export interface ExportCubeData {
name?: string;
from: Vec3;
to: Vec3;
rotation?: Vec3;
origin?: Vec3;
faces: Partial<Record<CubeFaceDirection, ExportFaceData>>;
}
export interface ExportMeshFaceData {
vertices: string[];
uv?: number[] | Record<string, number[]>; // per-vertex UV: array (in face.vertices order) or object (by vertex id)
textureKey?: string;
}
export interface ExportMeshData {
name?: string;
vertices: Record<string, Vec3>;
faces: Record<string, ExportMeshFaceData>;
}
export type ExportElement = ({ type: 'cube' } & ExportCubeData) | ({ type: 'mesh' } & ExportMeshData);
export interface ExportTexture {
key: string;
resName: string;
width: number;
height: number;
dataUrl?: string; // base64 data URL (for writing PNGs; not needed by the pure layer)
}// whether a group "cannot be exported" in the given mode and must fall back to OBJ:
// obj mode: everything; any mesh element (triangle faces); classic_java + any multi-axis cube;
// bedrock + >1 texture referenced
export function groupNeedsObj(elements: ExportElement[], mode: ExportMode): boolean;
// element rotation → Java model JSON rotation field: no rotation → undefined (omitted);
// new_java with multi-axis or any angle >45° → {x,y,z,origin}; otherwise single-axis → {angle,axis,origin}
export function rotationToJava(
rotation: Vec3 | undefined,
origin: Vec3 | undefined,
mode: ExportMode
): { angle?: number; axis?: 'x' | 'y' | 'z'; x?: number; y?: number; z?: number; origin: Vec3 } | undefined;// track-shape group id → exported model file name; null = not exported separately. z_ortho is not
// exported (blockstates rotate x_ortho 90°); ascending_* exports only the south variant ascending.json;
// teleport_x is not exported; all four crossing models are exported (cross_d1_* = positive diagonal,
// cross_d2_* = negative diagonal; zo = base "diagonal + Z straight", xo = it rotated 90° — diagonal + X),
// matching the reference Kuayue standard assets.
export const TRACK_MODEL_FILES: Record<string, string | null>;
export function cleanGroupName(name: string): string; // strips the (…)/(…) display suffix
export function modelFileName(id: string): string | null; // file name for a shape id
export function blockstatesFileName(trackId: string): string; // {trackId}_track.json
// strips extension, lowercases, non-[a-z0-9_] → _, unique within `used` (appends _1/_2… on collision)
export function textureResourceName(name: string, used: Set<string>): string;
// in-model texture path: {namespace}:{texture resource path}/{resName} (default block/track/{trackId})
export function textureResourcePath(namespace: string, trackId: string, resName: string, texturePath?: string): string;// variants combine shape × turn × waterlogged; shape=none → air model, the rest →
// {namespace}:{model resource path}/{model} (default block/track/{trackId}). shape=zo → x_ortho y:90;
// the four crossing shapes reference the four crossing models directly (no y rotation):
// cr_pdx→cross_d1_xo, cr_pdz→cross_d1_zo, cr_ndx→cross_d2_xo, cr_ndz→cross_d2_zo.
export function buildBlockstates(
namespace: string,
trackId: string,
modelPath?: string
): { variants: Record<string, { model: string; y?: number }> };// new_java adds format_version 1.21.11 + multi-axis {x,y,z}; classic_java omits format_version and uses
// single-axis rotation only. Elements must already be eligible cubes (meshes fell back to OBJ); UVs are
// converted from pixels to the 16-unit system.
export function buildJavaModelJson(opts: {
mode: ExportMode;
elements: ExportElement[];
textures: ExportTexture[];
textureSize: [number, number];
namespace: string;
trackId: string;
texturePathOf?: Record<string, string>; // texture key → resource directory (default block/track/{trackId})
}): Record<string, unknown>;The .obj/.mtl serialization itself lives in the build layer (src/build/export.ts →
exportGroupAsObj); this pure function builds the forge:obj reference JSON (model + flip_v +
textures), matching the Create/Kuayue examples.
export function buildObjReferenceJson(opts: {
namespace: string;
trackId: string;
shape: string;
textures: ExportTexture[];
texturePathOf?: Record<string, string>;
modelPath?: string; // model resource path (for blockstate references), default block/track/{trackId}
}): Record<string, unknown>;// cubes → a minecraft:geometry block model. Following Blockbench o6/r6: cube origin[0] negated (X mirror),
// pivot = rotation origin (X-mirrored) with rx/ry negated when rotated; per-face uv with up/down faces
// uv+=size and size negated. Elements must already be eligible cubes (meshes / multi-texture fell back to OBJ).
export function buildBedrockGeometry(opts: {
identifier: string;
elements: ExportElement[];
textureSize: [number, number];
}): Record<string, unknown>;
// blocks.json (behavior pack root, legacy aggregated format): one block per shape,
// identifier {ns}:{trackId}_{shape}; texturePath is relative to textures/ (written to
// textures/{texturePath}.png → "{texturePath}").
export function buildBedrockBlocksJson(opts: {
namespace: string;
trackId: string;
shapes: { id: string; texturePath: string }[];
}): Record<string, unknown>;