Skip to content

logic transform

laurel Lin edited this page Aug 22, 2026 · 3 revisions

src/logic/transform.ts — Geometric transforms

Pure functions on CubeSpec[], decoupled from Blockbench: translation edits from/to/origin directly; rotation returns CubeSpecs carrying a rotation field that the assembly layer expresses as Cube.rotation.

Copy & translate

export function cloneCubes(cubes: CubeSpec[]): CubeSpec[];
export function translate(cubes: CubeSpec[], offset: Vec3): CubeSpec[];
export function lift(cubes: CubeSpec[], dy: number): CubeSpec[];  // y-translate, positive up

Rotation

// sets rotation.y = angleDeg (ensuring origin), leaves from/to unchanged — Blockbench expresses it via
// Cube.rotation instead of recomputed coordinates
export function rotateY(cubes: CubeSpec[], angleDeg: number, origin: Vec3): CubeSpec[];

// X rotation for the ascending slope; preserves any existing Y rotation (yaw)
export function rotateX(cubes: CubeSpec[], angleDeg: number, origin: Vec3): CubeSpec[];

// rotates a vector by [rx,ry,rz] in X→Y→Z order (Minecraft's Cube.rotation order)
export function rotateVec(v: Vec3, rot: Vec3): Vec3;

Face UV transforms

transformFaceUV transforms a face's UV sampling under a cube rotation — the texture is "glued" to the volume, so after rotating, the same region stays on the same physical face while its normal/local UV axes change. For 90°-multiple axis rotations: pure rotation (det>0) keeps the uv box and adds the angle to face.rotation; reflection (det<0, e.g. side faces when rotating about Z) reverses the uv box's v (swap v0/v1) to express the mirror — Minecraft's face.rotation only supports 0/90/180/270.

export function transformFaceUV(
	dir: CubeFaceDirection,
	face: FaceSpec,
	rot: Vec3
): { dir: CubeFaceDirection; face: FaceSpec };

Mirroring

mirrorPartYz mirrors a part about the YZ plane through its lateral center (xMid) — "right rail = mirror of left rail" (Create's segment_left / segment_right are mirrors about the track centerline): geometry x → 2·xMid − x (from/to swapped), rotation [rx,−ry,−rz], east↔west faces swapped + u-axis reversed + rotation negated, mesh vertex x reflected + face vertex order reversed. Textures are unchanged; input not mutated. Mirroring about one's own center is an involution.

export function mirrorPartYz(part: PartModel): PartModel;

Rotation baking

// bakes 90°-multiple axis-aligned rotations into from/to (plain boxes, no rotation field), so derived
// shapes can add their own group rotation without overwriting the part's own orientation (e.g. a rail's
// built-in [0,-90,0] would otherwise be lost, leaving the rails parallel to the ties). Non-90° rotations
// are kept. Returns a new PartModel with recomputed bbox/xMid.
export function bakePartAxisAligned(part: PartModel): PartModel;

// bakes a −90° Y rotation into every unrotated cube (about `center`) and remaps each face's UV.
// Result: plain boxes without a rotation field, so later rotateY/rotateX composition can't overwrite.
// Direction mapping: north→east, south→west, east→south, west→north; up/down unchanged.
export function bakeRotateY90(cubes: CubeSpec[], center: Vec3): CubeSpec[];

Mesh transforms

rotateMesh bakes a rotation about a pivot into the vertex positions (world′ = pivot + R·(world−pivot), origin cleared) — required because Blockbench renders a mesh as origin + R(rotation)·vertices, which differs from the cube convention (Minecraft rotates about the origin with an implicit −origin), so a shape's group rotation can't be expressed via the mesh's rotation field with world-space vertices.

export function cloneMesh(mesh: MeshSpec): MeshSpec;
export function translateMesh(mesh: MeshSpec, offset: Vec3): MeshSpec;
export function liftMesh(mesh: MeshSpec, dy: number): MeshSpec;
export function rotateMesh(mesh: MeshSpec, rot: Vec3, pivot: Vec3): MeshSpec;

← Back to English API Reference

Clone this wiki locally