/** Slice rect [x, y, width, height] in source texture pixels. */ export type TextureSlice = [x:number, y:number, width:number, height:number] /** Block face slice for isometric block rendering. */ export interface BlockFaceSlice { slice: TextureSlice } /** * Block-style render config. When set, ItemCanvas uses an aux canvas to composite * top/left/right faces into an isometric icon instead of a single texture. * Useful for blocks in mineflayer connector where block texture atlas faces differ. */ export interface BlockTextureRender { /** Source texture URL or preloaded HTMLImageElement. */ source: string | HTMLImageElement top: BlockFaceSlice left: BlockFaceSlice right: BlockFaceSlice } export interface ItemStack { type: number count: number /** Snake_case item name, e.g. "diamond_sword". Used for texture lookup. */ name?: string metadata?: number nbt?: Record displayName?: string enchantments?: Array<{ name: string; level: number }> lore?: string[] durability?: number maxDurability?: number /** * Override texture lookup key. When set, this path is used instead of the item `name` * to resolve the item texture. Useful for custom resource packs or items that share a * type ID but have distinct textures (e.g. potions, spawn eggs, dyed armor). * * The value is passed directly to `TextureConfig.getItemTextureUrl`. * Example: `"item/dye_black"` or `"entity/spider/spider"` */ textureKey?: string /** * Direct texture override. When set, bypasses getItemTextureUrl. * - `string`: URL (data URL or http) used as img src. * - `HTMLImageElement`: preloaded image, drawn directly. */ texture?: string | HTMLImageElement /** * Block-style isometric render. When set, ItemCanvas uses a canvas pool to composite * top/left/right face slices into the icon. Use in mineflayer itemMapper for blocks. */ blockTexture?: BlockTextureRender /** * Arbitrary debug identifier exposed as a `data-debug` attribute on the slot element. * The mineflayer connector sets this to `":"` by default, making it easy * to inspect raw item IDs in browser DevTools without touching React internals. */ debugKey?: string } export interface SlotState { index: number item: ItemStack | null } export type MouseButton = 'left' | 'right' | 'middle' export type ClickMode = 'normal' | 'shift' | 'number' | 'middle' | 'drop' | 'drag' | 'double' export interface SlotClickEvent { slotIndex: number button: MouseButton mode: ClickMode numberKey?: number } export interface DragEvent { startSlot: number endSlot: number button: MouseButton } export type InventoryAction = | { type: 'click'; slotIndex: number; button: MouseButton; mode: ClickMode; numberKey?: number } | { type: 'drop'; slotIndex: number; all: boolean } | { type: 'drag'; slots: number[]; button: MouseButton } | { type: 'close' } | { type: 'trade'; tradeIndex: number } | { type: 'rename'; text: string } | { type: 'enchant'; enchantIndex: number } | { type: 'beacon'; primaryEffect: number; secondaryEffect: number } | { type: 'hotbar-swap'; slotIndex: number; hotbarSlot: number } /** Standalone hotbar HUD: change selected slot only (no window pick/swap). Slot index 36–44. */ | { type: 'hotbar-select'; slotIndex: number } /** Emitted by the Hotbar "open inventory" button; integrations (e.g. mineflayer) handle this. */ | { type: 'open-inventory' } export interface InventoryWindowState { windowId: number type: string title?: string slots: SlotState[] properties?: Record heldItem: ItemStack | null } export interface PlayerState { activeHotbarSlot: number inventory: SlotState[] } export interface TextureAtlas { url: string tileSize: number tilesPerRow: number } export type ScaleValue = number | string export interface InventoryGUIConfig { scale?: ScaleValue slotSize?: number showJEI?: boolean jeiPosition?: 'left' | 'right' showTooltips?: boolean resourcePackUrl?: string textureAtlas?: TextureAtlas } export interface SlotDefinition { index: number x: number y: number size?: number group: string label?: string acceptsItem?: (item: ItemStack) => boolean resultSlot?: boolean fuelSlot?: boolean } export interface ProgressBar { id: string x: number y: number width: number height: number direction: 'right' | 'up' | 'down' | 'left' textureX: number textureY: number emptyTextureX?: number emptyTextureY?: number /** Standalone sprite image path (mc-assets 1.20+ format). When set, used instead of clipping from the background texture. */ spriteTexture?: string getValue: (props: Record) => number getMax: (props: Record) => number } export interface EntityDisplayArea { x: number y: number width: number height: number } export interface InventoryTypeDefinition { name: string /** * Alternate type strings that resolve to this definition (e.g. protocol names like `crafting` → crafting_table). * Do not include `minecraft:` — that prefix is stripped before lookup. */ aliases?: string[] title: string backgroundTexture: string backgroundWidth: number backgroundHeight: number slots: SlotDefinition[] progressBars?: ProgressBar[] playerInventoryOffset?: { x: number; y: number } /** Pixel offset applied to the title position relative to the default (6px top, 8px left). */ titleOffset?: { x: number; y: number } properties?: Record windowType?: number | string hasTitle?: boolean extraData?: Record /** Bounds for the entity preview area (e.g. player model, horse model). */ entityDisplay?: EntityDisplayArea /** * Bundled placeholder image for the entity panel when `renderEntity` is not set. * Maps to files under `src/assets/entities/`. */ entityPlaceholder?: 'player' | 'horse' | 'llama' /** * When set, InventoryBackground will canvas-stitch the background texture: * top (title + N container rows) + bottom (player inventory section) from * the `generic_54.png` (176×222, 6-row) source. Applies only for N < 6. */ containerRows?: number } export interface RecipeGuide { title: string description?: string /** 'crafting' = 3×3 grid, 'smelting' = input+fuel→result, 'custom' = description only */ type: 'crafting' | 'smelting' | 'custom' /** For crafting: 9-element array (null = empty slot) */ ingredients?: (ItemStack | null)[] input?: ItemStack | null fuel?: ItemStack | null result?: ItemStack | null } /** A single entry in the recipe navigation stack */ export interface RecipeNavFrame { /** The item whose recipes/usages are being viewed */ item: { type: number; name: string; displayName: string; count?: number; metadata?: number } mode: 'recipes' | 'usages' guides: RecipeGuide[] /** Currently displayed guide index within `guides` */ guideIndex: number } export interface TradeOffer { inputItem1: ItemStack inputItem2: ItemStack | null outputItem: ItemStack disabled: boolean uses: number maxUses: number xp: number priceMultiplier: number demand: number specialPrice: number } export interface VillagerWindowState extends InventoryWindowState { trades: TradeOffer[] selectedTrade: number villagerLevel: number villagerXp: number isRegularVillager: boolean canRestock: boolean } export interface EnchantingWindowState extends InventoryWindowState { enchantmentOptions: Array<{ level: number enchantmentId: number enchantmentLevel: number requiredXp: number }> seed: number }