@minecraft/creator-tools
Version:
Minecraft Creator Tools command line and libraries.
295 lines (294 loc) • 11.5 kB
TypeScript
/**
* Model2DRenderer
*
* Renders Minecraft Bedrock geometry models to 2D SVG representations.
* Creates icon-style views of entities by projecting 3D geometry onto a 2D plane
* and sampling texture data for accurate coloring.
*
* FEATURES:
* ---------
* - Orthographic views: front, back, left, right, top, bottom
* - Isometric views: iso-front-right, iso-front-left, iso-back-right, iso-back-left
* (shows 3 faces at once for realistic 3D-like appearance)
* - Built-in unit cube support for standard block rendering
* - Proper depth sorting for occlusion (painter's algorithm)
* - Direct PNG and TGA texture loading (no browser required)
* - Support for bone rotations and bind_pose_rotation
* - Configurable scale and output dimensions
* - Optional depth shading effects
* - Pure Node.js - no Playwright/browser dependency needed
*
* USAGE:
* ------
* // Render a unit cube block (uses built-in geometry):
* const svg = Model2DRenderer.renderUnitCubeToSvg({
* viewDirection: 'iso-front-left',
* texturePngData: pngBuffer,
* outputWidth: 64,
* outputHeight: 64
* });
*
* // With raw PNG data (handles decoding automatically):
* const svg = Model2DRenderer.renderToSvg(geometry, {
* viewDirection: 'front',
* texturePngData: pngBuffer, // Uint8Array of PNG file contents
* outputWidth: 64,
* outputHeight: 64,
* depthShading: true
* });
*
* // Isometric view for Minecraft inventory-style 3D appearance:
* const svg = Model2DRenderer.renderToSvg(geometry, {
* viewDirection: 'iso-front-right', // Shows north + east + up faces
* texturePngData: pngBuffer,
* outputWidth: 64,
* outputHeight: 64
* });
*
* // With raw TGA data (async - use renderToSvgAsync):
* const svg = await Model2DRenderer.renderToSvgAsync(geometry, {
* viewDirection: 'front',
* textureTgaData: tgaBuffer, // Uint8Array of TGA file contents
* outputWidth: 64,
* outputHeight: 64
* });
*
* // With any image type (use textureData + textureFileType):
* const svg = await Model2DRenderer.renderToSvgAsync(geometry, {
* viewDirection: 'front',
* textureData: imageBuffer,
* textureFileType: 'tga', // or 'png'
* outputWidth: 64
* });
*
* // With pre-parsed texture pixels:
* const svg = Model2DRenderer.renderToSvg(geometry, {
* viewDirection: 'front',
* texturePixels: { width: 64, height: 64, pixels: rgbaData },
* outputWidth: 64,
* outputHeight: 64
* });
*
* // Without texture (uses fallback color):
* const svg = Model2DRenderer.renderToSvg(geometry, {
* viewDirection: 'front',
* fallbackColor: '#808080'
* });
*
* TEXTURE DATA FORMAT:
* --------------------
* Option 1: texturePngData - raw PNG file bytes as Uint8Array
* - Automatically decoded using pngjs (sync)
* - Fast, pure Node.js, no browser needed
*
* Option 2: textureTgaData - raw TGA file bytes as Uint8Array
* - Automatically decoded using @lunapaint/tga-codec (async)
* - Use renderToSvgAsync() or renderToDetailedSvgAsync()
*
* Option 3: textureData + textureFileType - generic image bytes
* - Works with 'png' or 'tga' file types
* - Use async methods for TGA support
*
* Option 4: texturePixels - pre-parsed RGBA pixel data
* - width: texture width in pixels
* - height: texture height in pixels
* - pixels: Uint8Array of RGBA values (4 bytes per pixel, row-major)
*
* LIMITATIONS:
* ------------
* - Rotation is handled but heavily rotated cubes may not project perfectly
* - No animation support (renders rest pose only)
* - Texture filtering is nearest-neighbor (pixel art style)
*
* Last Updated: December 2025
*/
import { IGeometry } from "./IModelGeometry";
import { ViewDirection } from "./ModelGeometryUtilities";
/**
* Pre-parsed texture pixel data.
*/
export interface ITexturePixels {
/** Texture width in pixels */
width: number;
/** Texture height in pixels */
height: number;
/** RGBA pixel data (4 bytes per pixel, row-major order) */
pixels: Uint8Array;
}
/**
* Options for 2D rendering
*/
export interface IModel2DRenderOptions {
/** View direction (default: 'front') */
viewDirection?: ViewDirection;
/** Raw PNG file data - will be decoded automatically using pngjs */
texturePngData?: Uint8Array;
/** Raw TGA file data - will be decoded automatically */
textureTgaData?: Uint8Array;
/**
* Raw texture file data with explicit file type.
* Alternative to texturePngData/textureTgaData when you have the data and type separately.
*/
textureData?: Uint8Array;
/** File type for textureData ('png' or 'tga') */
textureFileType?: string;
/** Pre-parsed texture pixel data (alternative to texturePngData) */
texturePixels?: ITexturePixels;
/** Texture width as defined in geometry (for UV mapping, default: from geometry or 64) */
textureWidth?: number;
/** Texture height as defined in geometry (for UV mapping, default: from geometry or 64) */
textureHeight?: number;
/** Output SVG width in pixels (default: 64) */
outputWidth?: number;
/** Output SVG height in pixels (default: 64) */
outputHeight?: number;
/** Whether to add depth shading (darker = further away) */
depthShading?: boolean;
/** Depth shading intensity (0-1, default: 0.3) */
depthShadingIntensity?: number;
/** Background color (default: transparent) */
backgroundColor?: string;
/** Padding in pixels around the model (default: 2) */
padding?: number;
/** Whether to include secondary faces (sides/top) for 3/4 view effect */
includeSecondaryFaces?: boolean;
/** Scale multiplier for output (default: auto-fit) */
scale?: number;
/** Fallback color when texture is not available */
fallbackColor?: string;
/**
* Perspective projection strength (0-1, default: 0 = orthographic).
* A value of 0 uses pure orthographic projection (no foreshortening).
* A value of 1 uses strong perspective with visible vanishing point effect.
* Recommended range: 0.1-0.3 for subtle perspective, 0.5+ for dramatic effect.
*/
perspectiveStrength?: number;
/**
* Focal length for perspective projection (default: 100).
* Smaller values create more dramatic perspective (wide-angle lens effect).
* Larger values create flatter perspective (telephoto lens effect).
* Only applies when perspectiveStrength > 0.
*/
focalLength?: number;
/**
* Texture sampling resolution per face (default: 1 = single color per face).
* Higher values divide each face into a grid for more detailed texture representation.
* - 1: Single averaged color per face (fastest, smallest SVG)
* - 2: 2x2 grid = 4 samples per face
* - 4: 4x4 grid = 16 samples per face (good balance of quality/size)
* - 8: 8x8 grid = 64 samples per face (high quality)
* Only applies to non-isometric views. Isometric views use single color for cleaner polygons.
*/
textureSampleResolution?: number;
}
/**
* Static class for rendering Minecraft geometry models to 2D SVG.
* Pure Node.js implementation - no browser/Playwright required.
*/
export default class Model2DRenderer {
/**
* Standard unit cube geometry (16x16x16 Minecraft units = 1 block).
* Can be used directly with renderToSvg for unit cube blocks.
*/
static readonly UNIT_CUBE_GEOMETRY: IGeometry;
/**
* Render a unit cube block to SVG.
* Convenience method that uses the standard unit cube geometry.
*
* @param options Rendering options (same as renderToSvg, but geometry is provided)
* @returns SVG string
*/
static renderUnitCubeToSvg(options?: IModel2DRenderOptions): string;
/**
* Async version of renderUnitCubeToSvg that supports TGA textures.
*
* @param options Rendering options
* @returns SVG string
*/
static renderUnitCubeToSvgAsync(options?: IModel2DRenderOptions): Promise<string>;
/**
* Decode PNG data to RGBA pixels using pngjs.
* This is a synchronous operation - fast and doesn't require a browser.
* Only works in Node.js environment - returns undefined in browser.
*
* @param pngData Raw PNG file bytes
* @returns Decoded texture pixels, or undefined if decoding fails
* @deprecated Use ImageCodec.decodePng() directly instead
*/
static decodePng(pngData: Uint8Array): ITexturePixels | undefined;
/**
* Decode TGA data to RGBA pixels.
* Uses ImageCodec for decoding.
*
* @param tgaData Raw TGA file bytes
* @returns Decoded texture pixels, or undefined if decoding fails
* @deprecated Use ImageCodec.decodeTga() directly instead
*/
static decodeTga(tgaData: Uint8Array): Promise<ITexturePixels | undefined>;
/**
* Decode image data (PNG or TGA) to RGBA pixels.
* Uses ImageCodec for decoding.
*
* @param data Raw image file bytes
* @param fileType File extension ('png' or 'tga')
* @returns Decoded texture pixels, or undefined if decoding fails
* @deprecated Use ImageCodec.decode() directly instead
*/
static decodeTexture(data: Uint8Array, fileType: string): Promise<ITexturePixels | undefined>;
/**
* Render a geometry model to SVG string.
* Uses average color sampling per face for efficient rendering.
*
* @param geometry The geometry definition to render
* @param options Rendering options
* @returns SVG string
*/
static renderToSvg(geometry: IGeometry, options?: IModel2DRenderOptions): string;
/**
* Async version of renderToSvg that supports TGA textures.
* Use this when you have a TGA texture that needs to be decoded.
*
* @param geometry The geometry definition to render
* @param options Rendering options (can include textureTgaData or textureData+textureFileType)
* @returns SVG string
*/
static renderToSvgAsync(geometry: IGeometry, options?: IModel2DRenderOptions): Promise<string>;
/**
* Render a geometry model to SVG with per-pixel texture sampling.
* Creates a more detailed rendering by sampling texture for each output pixel.
*
* @param geometry The geometry definition to render
* @param options Rendering options
* @returns SVG string with detailed pixel rendering
*/
static renderToDetailedSvg(geometry: IGeometry, options?: IModel2DRenderOptions): string;
/**
* Async version of renderToDetailedSvg that supports TGA textures.
* Use this when you have a TGA texture that needs to be decoded.
*
* @param geometry The geometry definition to render
* @param options Rendering options (can include textureTgaData or textureData+textureFileType)
* @returns SVG string with detailed pixel rendering
*/
static renderToDetailedSvgAsync(geometry: IGeometry, options?: IModel2DRenderOptions): Promise<string>;
/**
* Sample a single pixel from the texture.
*/
private static _sampleTexturePixel;
/**
* Sample the average color from a texture region.
*/
private static _sampleTextureAverageColor;
/**
* Apply shading to a color.
*/
private static _shadeColor;
/**
* Calculate auto scale to fit geometry in output dimensions.
*/
private static _calculateAutoScale;
/**
* Get the 2D bounding box of projected faces.
*/
private static _getProjectedBounds;
}