npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

game-locker-ui

v0.1.0

Published

A React component kit for building game locker / loadout UIs. Fully themeable via CSS custom properties, written in TypeScript.

Downloads

106

Readme

game-locker-ui

A React component kit for building game locker / loadout UIs. Fully themeable via CSS custom properties, written in TypeScript.

React TypeScript Tailwind CSS


Installation

npm install game-locker-ui

React 18 is a peer dependency — make sure it is already installed in your project.


Quick Start

import { useState } from 'react';
import {
  LockerThemeProvider,
  LockerHeader,
  LockerItemSlots,
  CharacterDisplay,
  LockerRightPanel,
} from 'game-locker-ui';
import 'game-locker-ui/styles';

export default function App() {
  const [activeTab, setActiveTab] = useState('locker');

  return (
    <LockerThemeProvider>
      <div style={{ display: 'flex', flexDirection: 'column', height: '100vh' }}>
        <LockerHeader activeTab={activeTab} onTabChange={setActiveTab} />
        <div style={{ display: 'flex', flex: 1, overflow: 'hidden' }}>
          <LockerItemSlots />
          <CharacterDisplay />
          <LockerRightPanel />
        </div>
      </div>
    </LockerThemeProvider>
  );
}

Important: Import 'game-locker-ui/styles' once at the top of your app. This injects the --locker-* CSS custom properties that all components depend on.


Components

LockerThemeProvider

Wrap your app (or any subtree) with this provider to apply theme colors. All --locker-* CSS variables are scoped to the wrapper element — they don't pollute :root and are SSR-safe.

<LockerThemeProvider theme={{ bgDark: '#6c3483', selectionColor: '#00ffff' }}>
  {/* components pick up the overrides automatically */}
</LockerThemeProvider>

| Prop | Type | Default | |------|------|---------| | theme | LockerTheme | all defaults (see Theming) | | children | ReactNode | — |


LockerHeader

The top navigation bar with tab switching, a menu button with notification badge, and a currency counter.

<LockerHeader
  activeTab="locker"
  onTabChange={(id) => console.log(id)}
  vbucks={1200}
/>

| Prop | Type | Default | |------|------|---------| | activeTab | string | — (required) | | onTabChange | (id: string) => void | — (required) | | tabs | LockerTab[] | 7 default tabs (see below) | | vbucks | number | 800 | | notificationCount | number | 1 |

Default tabs:

| id | label | |----|-------| | play | PLAY | | battlepass | BATTLE PASS | | compete | COMPETE | | locker | LOCKER | | itemshop | ITEM SHOP (has notification badge) | | career | CAREER (has notification badge) | | vbucks | V-BUCKS |


LockerItemSlots

The left panel containing the main loadout row, emote wheel, miscellaneous slots, and a favorites button.

<LockerItemSlots
  topRowItems={myOutfits}
  onItemSelect={(item) => console.log(item)}
  favoriteActive
  onFavoriteClick={() => {}}
/>

| Prop | Type | Default | |------|------|---------| | topRowItems | ItemSlot[] | 5 placeholder slots (outfit, backbling, pickaxe, glider, contrail) | | emoteSlots | ItemSlot[] | 6 placeholder slots (3 filled, 3 empty) | | miscSlots | ItemSlot[] | 9 placeholder slots | | onItemSelect | (item: ItemSlot) => void | — | | favoriteActive | boolean | false | | onFavoriteClick | () => void | — |

Supply an image URL on any ItemSlot to render it inside the slot:

const myItems: ItemSlot[] = [
  { id: '1', type: 'outfit', selected: true, image: 'https://example.com/skin.png', label: 'Dark Knight' },
  { id: '2', type: 'backbling' },
];

CharacterDisplay

The center panel showing the character preview image, name, rarity, and category label.

<CharacterDisplay
  characterName="RAVEN"
  rarityLabel="LEGENDARY"
  categoryLabel="OUTFIT"
  characterImage="https://example.com/raven.png"
/>

| Prop | Type | Default | |------|------|---------| | characterImage | string | Unsplash placeholder | | characterName | string | 'SELENA' | | rarityLabel | string | 'EPIC' | | categoryLabel | string | 'OUTFIT' |


LockerRightPanel

The right panel with preset action buttons (Load, Save, Random).

<LockerRightPanel
  onLoad={() => loadPreset()}
  onSave={() => savePreset()}
  onRandom={() => randomize()}
/>

| Prop | Type | Default | |------|------|---------| | title | string | 'PRESETS' | | loadLabel | string | 'LOAD' | | saveLabel | string | 'SAVE' | | randomLabel | string | 'RANDOM' | | onLoad | () => void | — | | onSave | () => void | — | | onRandom | () => void | — |


Theming

All colors are driven by CSS custom properties. Import the stylesheet and override any variable on a parent element — no CSS recompile needed.

CSS variables

| Variable | Default | Used for | |----------|---------|----------| | --locker-bg-light | #4a9fdb | Background gradient top, slot borders | | --locker-bg-mid | #2b7fd4 | Background gradient middle, slot fill | | --locker-bg-dark | #1e5fb8 | Header, slot fill, button backgrounds | | --locker-bg-darker | #0d4494 | Currency counter background | | --locker-selection | #ff00ff | Selected slot border and glow | | --locker-badge | #ffd700 | Notification badges | | --locker-glow | #5aaee8 | Character display radial glow | | --locker-font | 'Luckiest Guy', ... | Heading font stack |

Via LockerThemeProvider (recommended)

<LockerThemeProvider
  theme={{
    bgDark: '#6c3483',
    bgMid: '#8e44ad',
    bgLight: '#a569bd',
    bgDarker: '#4a235a',
    selectionColor: '#00ffff',
    badgeColor: '#ff6b00',
  }}
>
  <YourApp />
</LockerThemeProvider>

Via plain CSS (alternative)

.my-custom-locker {
  --locker-bg-dark: #1a3a2a;
  --locker-selection: #00ff88;
}

useLockerTheme() hook

Read the current resolved theme values inside any child component:

import { useLockerTheme } from 'game-locker-ui';

function MyComponent() {
  const theme = useLockerTheme();
  return <div style={{ color: theme.selectionColor }}>Selected</div>;
}

TypeScript Types

import type { ItemSlot, ItemSlotType, LockerTab, LockerTheme } from 'game-locker-ui';

type ItemSlotType =
  | 'outfit' | 'backbling' | 'pickaxe' | 'glider' | 'contrail'
  | 'emote' | 'spray' | 'emoticon' | 'banner' | 'music';

interface ItemSlot {
  id: string;
  type: ItemSlotType;
  selected?: boolean;
  image?: string;
  isEmpty?: boolean;
  label?: string;
}

interface LockerTab {
  id: string;
  label: string;
  hasNotification?: boolean;
}

interface LockerTheme {
  bgLight?: string;
  bgMid?: string;
  bgDark?: string;
  bgDarker?: string;
  selectionColor?: string;
  badgeColor?: string;
  fontFamily?: string;
}

Development

npm install       # install dependencies
npm run dev       # start demo app at localhost:5173
npm run build     # build demo app → dist-demo/
npm run build:lib # build npm package → dist/

The demo app (src/app/App.tsx) shows a working instance of the full locker layout and serves as a live development environment.


License

MIT