JSPM

  • Created
  • Published
  • Downloads 136
  • Score
    100M100P100Q133667F
  • License MIT

Package Exports

    This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (minecraft-inventory) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

    Readme

    minecraft-inventory

    A flexible, scalable React library for rendering Minecraft inventory GUIs. Designed for integration into real Minecraft clients (e.g., mineflayer bots, web clients) without using CSS transform: scale — all sizing is driven by CSS custom properties.

    Features

    • All standard inventory types (chest, furnace, crafting table, villager trades, enchanting table, brewing stand, anvil, smithing table, horse, beacon, and more)
    • CSS variable–based scaling — no layout jank, no transform: scale
    • <img>-rendered item textures with automatic items/blocks/ fallback (via PrismarineJS asset mirror by default)
    • Tooltips that follow the cursor, matching the original Minecraft style
    • Full keyboard support: number keys (1-9) to swap hotbar, Q to drop, double-click to collect, scroll wheel to pick/place
    • Mobile support: tap to open a context menu (take all / half / custom amount / drop)
    • Optional JEI (item browser) panel on the left or right
    • Bot connector layer — plugs into a mineflayer bot or any custom server connection
    • Demo connector with action logging for local development
    • Extendable registry — add new inventory types in one place

    Quick Start (React)

    import React from 'react'
    import { createRoot } from 'react-dom/client'
    import { InventoryGUI, createDemoConnector } from 'minecraft-inventory'
    
    const connector = createDemoConnector({
      windowType: 'chest',
      windowTitle: 'My Chest',
      slots: [
        { index: 0, item: { type: 265, name: 'iron_ingot', count: 32, displayName: 'Iron Ingot' } },
        // ...more slots
      ],
    })
    
    function App() {
      return (
        <InventoryGUI
          type="chest"
          connector={connector}
          scale={2}
          showJEI
          jeiItems={[
            { type: 1, name: 'stone', displayName: 'Stone', count: 1 },
            { type: 4, name: 'cobblestone', displayName: 'Cobblestone', count: 1 },
          ]}
        />
      )
    }
    
    // Mount into the DOM
    createRoot(document.getElementById('root')!).render(<App />)

    Quick Start (No React — programmatic)

    If you don't use React, use the mountInventory helper:

    <div id="inventory"></div>
    <script type="module">
      import { mountInventory, createDemoConnector } from 'minecraft-inventory'
    
      const connector = createDemoConnector({
        windowType: 'chest',
        windowTitle: 'My Chest',
        slots: [
          { index: 0, item: { type: 265, name: 'iron_ingot', count: 32, displayName: 'Iron Ingot' } },
        ],
      })
    
      const inv = mountInventory(document.getElementById('inventory'), {
        type: 'chest',
        connector,
        scale: 2,
      })
    
      // Update props later
      inv.update({ scale: 3 })
    
      // Destroy when done
      inv.destroy()
    </script>

    Installation

    npm install minecraft-inventory
    # or
    pnpm add minecraft-inventory

    Core API

    <InventoryGUI> — All-in-one component

    <InventoryGUI
      type="chest"                    // Inventory type name (see registry)
      title="My Chest"                // Override window title
      slots={[...]}                   // Optional: provide slots directly
      properties={{ litTime: 100 }}   // Optional: progress bar data
      connector={connector}           // Optional: bot connector
      scale={2}                       // Scale multiplier (default: 2)
      showJEI={false}                 // Show item browser panel
      jeiItems={[...]}                // Items to show in JEI
      jeiPosition="right"             // 'left' | 'right'
      textureBaseUrl="/assets/mc"     // Override texture base URL
      enableKeyboardShortcuts={true}
      onClose={() => {}}
    />

    <InventoryOverlay> — Full-screen overlay with backdrop

    Renders the inventory centered on screen with a semi-transparent backdrop. Clicking outside drops the held item or closes the window.

    import { InventoryOverlay, InventoryProvider, ScaleProvider, TextureProvider } from 'minecraft-inventory'
    
    <TextureProvider>
      <ScaleProvider scale={2}>
        <InventoryProvider connector={connector}>
          <InventoryOverlay
            type="chest"
            showBackdrop            // default: true (50% black)
            backdropColor="rgba(0,0,0,0.5)"
            showHotbar              // default: true
            showJEI
            jeiItems={items}
            jeiPosition="right"
            onClose={() => console.log('closed')}
          >
            {/* Extra children (e.g. notes panel) are rendered inside the centered anchor */}
          </InventoryOverlay>
        </InventoryProvider>
      </ScaleProvider>
    </TextureProvider>

    Manual composition

    For full control, use the provider components and compose manually:

    import {
      TextureProvider, ScaleProvider, InventoryProvider,
      InventoryWindow, Hotbar, HUD, CursorItem, JEI,
    } from 'minecraft-inventory'
    
    function MyInventory({ connector }) {
      return (
        <TextureProvider baseUrl="https://example.com/assets">
          <ScaleProvider scale={2}>
            <InventoryProvider connector={connector}>
              <div style={{ display: 'flex', gap: 8 }}>
                <InventoryWindow type="furnace" />
                <JEI items={allItems} position="right" />
              </div>
              <Hotbar />
              <HUD />
              <CursorItem />
            </InventoryProvider>
          </ScaleProvider>
        </TextureProvider>
      )
    }

    Scaling

    Scale is driven entirely by CSS custom properties — no transform: scale. Changing the scale prop recalculates all size tokens:

    Variable Default (scale=2)
    --mc-scale 2
    --mc-slot-size 36px (18 × scale)
    --mc-font-size 14px (7 × scale)
    --mc-pixel 2px
    // Changing scale re-renders the whole GUI at new dimensions
    <InventoryGUI type="chest" scale={3} />

    Textures

    By default, item textures are fetched from the PrismarineJS Minecraft assets mirror on GitHub:

    https://raw.githubusercontent.com/PrismarineJS/minecraft-assets/master/data/1.21.4/item/{name}.png

    Provide name on each ItemStack to use the correct asset:

    { type: 276, name: 'diamond_sword', count: 1, displayName: 'Diamond Sword' }

    To use local textures (e.g., from a resource pack server):

    <InventoryGUI
      type="chest"
      textureBaseUrl="/assets/minecraft"
      // → /assets/minecraft/item/diamond_sword.png
    />

    For full control, pass a custom texture config overriding any or all URL resolvers:

    import { TextureProvider } from 'minecraft-inventory'
    
    // Option A — simple base URL (all textures served from your CDN/server)
    <TextureProvider baseUrl="https://yourserver.com/mc-assets/1.21.4">
      {/* item textures: /mc-assets/1.21.4/items/{name}.png           */}
      {/* block textures: /mc-assets/1.21.4/blocks/{name}.png         */}
      {/* GUI textures: /mc-assets/1.21.4/textures/{path}.png         */}
      <InventoryWindow type="chest" />
    </TextureProvider>
    
    // Option B — replace individual resolvers (config is merged with defaults)
    <TextureProvider config={{
      getItemTextureUrl: ({ type, name }) =>
        `https://cdn.example.com/items/${name ?? type}.png`,
    
      getBlockTextureUrl: ({ type, name }) =>
        `https://cdn.example.com/blocks/${name ?? type}.png`,
    
      // version param lets you vary GUI textures per container (1.16.4, 1.21.4, etc.)
      getGuiTextureUrl: (path, version = '1.16.4') =>
        `https://cdn.example.com/gui/${version}/${path}.png`,
    }}>
      <InventoryWindow type="furnace" />
    </TextureProvider>
    
    // Option C — completely static local assets (no CDN)
    <TextureProvider config={{
      baseUrl: '/assets',
      getItemTextureUrl: ({ name, type }) => `/assets/items/${name ?? type}.png`,
      getBlockTextureUrl: ({ name, type }) => `/assets/blocks/${name ?? type}.png`,
      getGuiTextureUrl: (path) => `/assets/gui/${path}.png`,
    }}>
      <InventoryWindow type="chest" />
    </TextureProvider>

    Per-container texture version: Each inventory definition can carry a guiTextureVersion string (e.g. '1.21.4') that is passed to getGuiTextureUrl as the second argument. Older containers default to '1.16.4'; newer ones (crafter, new smithing table) use '1.21.4'. Specify it when registering custom containers.


    Connector

    The connector is the bridge between the GUI and a Minecraft server or bot.

    Mineflayer connector

    import { createMineflayerConnector } from 'minecraft-inventory'
    import mineflayer from 'mineflayer'
    
    const bot = mineflayer.createBot({ ... })
    
    bot.on('windowOpen', (window) => {
      const connector = createMineflayerConnector(bot)
    
      // Mount <InventoryGUI connector={connector} type={window.type} />
    })

    The connector translates GUI actions (slot clicks, drag, drop, etc.) into bot.clickWindow() calls and subscribes to mineflayer inventory events to keep the GUI in sync.

    Demo connector (for local testing)

    import { createDemoConnector } from 'minecraft-inventory'
    
    const connector = createDemoConnector({
      windowType: 'crafting_table',
      windowTitle: 'Crafting',
      slots: [...],
      onAction: (entry) => {
        console.log(entry.description, entry.action)
      },
    })
    
    // Update slots programmatically:
    connector.updateSlots(newSlots)
    connector.setHeldItem({ type: 264, name: 'diamond', count: 1 })
    connector.openWindow('furnace', 'Furnace', furnaceSlots)
    connector.closeWindowExternal()

    Custom connector

    Implement the InventoryConnector interface for any other backend:

    import type { InventoryConnector } from 'minecraft-inventory'
    
    const myConnector: InventoryConnector = {
      getWindowState: () => ({ windowId: 1, type: 'chest', slots: [...], heldItem: null }),
      getPlayerState: () => null,
      sendAction: async (action) => {
        // send action to server
        console.log('action', action)
      },
      closeWindow: () => {},
      subscribe: (listener) => {
        // call listener({ type: 'windowUpdate', state }) on changes
        return () => {} // cleanup
      },
    }

    Keyboard Shortcuts (Desktop)

    Key Action
    Left click Pick up all / place all
    Right click Pick up half / place one
    Shift + Left click Transfer to/from container
    Double click Collect all of same item type
    1–9 (while hovering) Swap slot with hotbar slot N
    Q (while hovering) Drop one item
    Ctrl+Q Drop entire stack
    Scroll up Pick up one more (right-click equivalent)
    Scroll down Put one back
    Esc Close window (onClose callback)

    Mobile Support

    On touch devices, tapping a slot with no held item opens a context menu instead of immediately picking up the item. The menu appears to the side in landscape or below in portrait.

    Context menu options:

    • Take All — picks up the entire stack
    • Take Half — picks up half
    • Take Amount…window.prompt to enter a custom quantity
    • Drop — drops the stack from the slot
    • Cancel

    When you have a held item, tapping a slot places/transfers it (same as left-click on desktop).


    JEI — Item Browser

    import { JEI } from 'minecraft-inventory'
    
    const items = [
      { type: 264, name: 'diamond', displayName: 'Diamond' },
      { type: 265, name: 'iron_ingot', displayName: 'Iron Ingot' },
      // ...
    ]
    
    <JEI
      items={items}
      position="right"           // 'left' | 'right'
      onItemClick={(item) => {}} // left-click handler
      onItemMiddleClick={(item) => {}} // middle-click handler
    />

    Use the search bar to filter by display name or item name. Scroll wheel or arrow buttons to paginate.


    Adding New Inventory Types

    All inventory types live in a single registry file:

    src/registry/inventories.ts

    Add a new entry to the inventoryDefinitions object:

    export const inventoryDefinitions: Record<string, InventoryTypeDefinition> = {
      // ... existing types ...
    
      my_custom_chest: {
        name: 'my_custom_chest',
        title: 'Custom Chest',
        backgroundTexture: 'gui/container/my_custom_chest',  // path under textures/
        backgroundWidth: 176,
        backgroundHeight: 166,
        includesPlayerInventory: true,
        includesHotbar: true,
        slots: [
          // Custom container slots (indices 0-N)
          ...gridSlots(0, 9, 3, 8, 18, 'container'),
          // Player inventory (adjust indices to match server protocol)
          ...playerInv(84, 27, 54),
        ],
      },
    }

    Slot index conventions:

    • Container slots always start at 0
    • Player inventory and hotbar indices vary by window type (match the server protocol)
    • Use playerInv(yPos, invStartIndex, hotbarStartIndex) for the standard 3×9 + hotbar layout

    Progress bars (for furnaces, brewing stands, etc.):

    progressBars: [
      {
        id: 'cook_arrow',
        x: 79, y: 34, width: 24, height: 16,
        direction: 'right',            // 'right' | 'up' | 'down' | 'left'
        textureX: 176, textureY: 14,   // source coords in background texture
        getValue: (props) => props.cookingProgress ?? 0,
        getMax: (props) => props.totalCookTime || 200,
      },
    ],

    Properties (data slots from server):

    properties: {
      cookingProgress: { dataSlot: 2, description: 'Cook progress (0-200)' },
      totalCookTime: { dataSlot: 3, description: 'Total cook time' },
    },

    Registering at runtime (optional, for plugins/mods):

    import { registerInventoryType } from 'minecraft-inventory'
    
    registerInventoryType({
      name: 'my_mod_inventory',
      title: 'Mod Inventory',
      backgroundTexture: 'gui/container/my_mod',
      backgroundWidth: 176,
      backgroundHeight: 166,
      slots: [...],
    })

    Then use it anywhere:

    <InventoryGUI type="my_mod_inventory" connector={connector} />

    ItemStack Type

    interface ItemStack {
      type: number        // Numeric item ID
      name?: string       // Snake_case name, e.g. 'diamond_sword' (used for texture URL)
      count: number
      metadata?: number
      nbt?: Record<string, unknown>
      displayName?: string
      enchantments?: Array<{ name: string; level: number }>
      lore?: string[]
      durability?: number        // Current durability value
      maxDurability?: number     // Max durability (renders bar when < max)
    }

    Project Structure

    src/
      index.tsx                  # Library entry point / exports
      types.ts                   # Core TypeScript types
      registry/
        index.ts                 # registerInventoryType / getInventoryType
        inventories.ts           # All built-in inventory type definitions ← ADD NEW TYPES HERE
      components/
        InventoryWindow/         # Main window renderer
        Slot/                    # Individual slot (click/drag/keyboard/mobile)
        ItemCanvas/              # Canvas-based item texture rendering
        Tooltip/                 # Cursor-following item tooltip
        JEI/                     # Item browser panel
        Hotbar/                  # Hotbar with active slot indicator
        HUD/                     # XP bar
        CursorItem/              # Floating item following mouse cursor
      context/
        InventoryContext.tsx      # Shared state (held item, hover, drag)
        ScaleContext.tsx          # CSS variable scale provider
        TextureContext.tsx        # Texture URL resolver
      connector/
        types.ts                 # InventoryConnector interface
        mineflayer.ts            # Mineflayer bot adapter
        demo.ts                  # Demo connector with action log
      hooks/
        useMobile.ts
        useKeyboardShortcuts.ts
      styles/
        tokens.css               # CSS custom property definitions
    playground/
      src/
        App.tsx                  # Interactive playground / demo
        mockItems.ts             # Sample items for testing

    Contributing

    Running the playground

    pnpm install
    pnpm dev
    # Opens at http://localhost:3200

    Adding a new inventory type

    1. Open src/registry/inventories.ts
    2. Add a new key to inventoryDefinitions (see template above)
    3. Test it in the playground by adding it to INVENTORY_TYPES in playground/src/App.tsx
    4. Submit a PR with the new type and sample mock slots in playground/src/mockItems.ts

    Slot index reference

    Each Minecraft window type has a fixed slot layout defined by the server protocol. The indices must match prismarine-windows / mineflayer slot numbering. Cross-reference with:

    • prismarine-windows for JS slot maps
    • Minecraft source: net/minecraft/world/inventory/ for the canonical layout

    Connector protocol

    When implementing a custom connector, actions have these shapes:

    Action type Fields
    click slotIndex, button ('left'/'right'/'middle'), mode ('normal'/'shift'/'double'/'number'/'drop'), numberKey?
    drop slotIndex, all (boolean)
    drag slots (number[]), button
    trade tradeIndex
    rename text
    enchant enchantIndex (0/1/2)
    beacon primaryEffect, secondaryEffect
    hotbar-swap slotIndex, hotbarSlot (0-8)
    close

    License

    MIT