Adding New Cosmetics
Relevant source files
The following files were used as context for generating this wiki page:- src/store/CosmeticsStore.ts
- src/components/cosmeticsScreen/CosmeticsPicker.ts
- src/components/character/Hat.ts
- src/screens/CosmeticsScreen.ts
- src/components/character/Character.ts
- src/components/character/Shirt.ts
- src/components/character/Pants.ts
- src/components/character/CharacterBase.ts
- src/components/cosmeticsScreen/CosmeticsTypePicker.ts
- src/components/cosmeticsScreen/SkinColorPicker.ts
The cosmetics system allows players to customize their in-game character's appearance. This includes changing the character's hat, shirt, pants, and skin color. The system is designed to be easily extensible, allowing developers to add new cosmetic items by modifying a central data definition file.
Player selections are managed by the CosmeticsStore, which persists the chosen configuration in a browser cookie. The CosmeticsScreen provides the user interface for making selections, and the Character component, along with its sub-components, is responsible for rendering the customized appearance in-game.
System Architecture
The cosmetics system is divided into three main parts: data management, user interface, and character rendering. This separation of concerns simplifies the process of adding new cosmetic items.
Data and State Management (CosmeticsStore)
The CosmeticsStore is the single source of truth for all cosmetic data and the player's current selections. It defines the available items, manages the application state, and handles persistence.
Sources: src/store/CosmeticsStore.ts
Data Structures
Cosmetic items are categorized into types: hat, shirt, and pants. Each category has a corresponding enum to identify items, a data interface, and an array that holds the metadata for each item, including its ID and sprite path.
The main data structures are:
| Structure | Type | Description |
|---|---|---|
CosmeticsTypes | type | A string literal type for cosmetic categories: 'hat' | 'shirt' | 'pants'. |
Hats, Shirts, Pants | enum | Enums that provide unique identifiers for each cosmetic item within a category. |
HatData, ShirtData, PantsData | interface | Interfaces defining the shape of cosmetic item data, including id and sprite. |
hatsData, shirtsData, pantsData | Array | Arrays containing the definitions for all available items in each category. |
SKIN_COLORS | const | A tuple of numbers [1, 2, 3, 4, 5] representing available skin tones. |
Sources: src/store/CosmeticsStore.ts:15-111
The following diagram illustrates the relationship between these data structures.
This diagram shows how each data array (hatsData, shirtsData, pantsData) is a collection of objects conforming to their respective data interfaces (HatData, ShirtData, PantsData), which in turn use enums for unique identification.
State Management
The CosmeticsStore class extends a generic Store and manages the CosmeticsStoreContent object, which represents the currently selected cosmetics.
| Property | Type | Description |
|---|---|---|
hat | Hats | The ID of the currently equipped hat. |
shirt | Shirts | The ID of the currently equipped shirt. |
pants | Pants | The ID of the currently equipped pants. |
skinColor | SkinColors | The ID of the currently selected skin color. |
Sources: src/store/CosmeticsStore.ts:113-118
The CosmeticsStore class handles initializing state (either randomly or from a cookie), updating state when a user makes a selection, and saving the configuration back to a cookie.
This diagram shows the key methods and properties of the CosmeticsStore class, which is central to managing cosmetic state.
Sources: src/store/CosmeticsStore.ts:120-258
User Interface
The UI for cosmetic selection is built from several components, orchestrated by the CosmeticsScreen.
Sources: src/screens/CosmeticsScreen.ts, src/components/cosmeticsScreen/CosmeticsPicker.ts, src/components/cosmeticsScreen/CosmeticsTypePicker.ts, src/components/cosmeticsScreen/SkinColorPicker.ts
The following diagram shows the hierarchy of UI components involved in the cosmetics screen.
This diagram illustrates how the CosmeticsScreen assembles various sub-components to create the customization interface.
Sources: src/screens/CosmeticsScreen.ts:28-80, src/components/cosmeticsScreen/CosmeticsPicker.ts:38-115
Item Selection Flow
When a user interacts with the CosmeticsPicker, it triggers updates in the CosmeticsStore, which causes the character preview to re-render with the new selection.
- The user clicks an icon in
CosmeticsTypePicker(e.g., 'hat'). CosmeticsTypePicker's callback updates theactivetype inCosmeticsPicker.CosmeticsPickerre-renders, displaying the list of available hats fromhatsData.- The user clicks on a specific hat sprite.
- The
EventListenerfor that sprite calls the appropriate setter method on theCosmeticsStore(e.g.,cosmeticsStore.setHat(...)). - The
CosmeticsStoreupdates its state and saves the new configuration to the cookie. - The
Charactercomponent, which subscribes to the store, re-renders to display the new hat.
The sequence diagram below visualizes this interaction.
This diagram shows the data flow when a user selects a cosmetic item.
Sources: src/components/cosmeticsScreen/CosmeticsPicker.ts:95-112, src/store/CosmeticsStore.ts:192-201
Character Rendering
The Character component is a composite that assembles the character's base body and all cosmetic items. Each cosmetic item is its own component (Hat, Shirt, Pants) that is responsible for rendering a single sprite.
Sources: src/components/character/Character.ts, src/components/character/Hat.ts, src/components/character/Shirt.ts, src/components/character/Pants.ts, src/components/character/CharacterBase.ts
Character.ts: This component includesCharacterBase,Pants,Shirt, andHatas children in the correct rendering order.CharacterBase.ts: Renders the body and eyes. It readsskinColorfrom theCosmeticsStoreto select one of the five base character sprites (e.g.,base_character_1.png).Hat.ts,Shirt.ts,Pants.ts: These simple components each fetch the currently active item's data from theCosmeticsStore(e.g.,cosmeticsStore.activeHat) and render itssprite. If no item is selected, the sprite source is an empty string, and nothing is rendered.
This diagram shows the composition of the Character component and how its children depend on the CosmeticsStore for their appearance.
Sources: src/components/character/Character.ts:22-50, src/components/character/Hat.ts:16-22, src/components/character/CharacterBase.ts:24-35
How to Add a New Cosmetic Item
Adding a new cosmetic item is a straightforward process that primarily involves updating the central data definitions in CosmeticsStore.ts. The UI and rendering logic will automatically incorporate the new item.
The following steps use a new hat as an example, but the process is identical for shirts and pants.
Step 1: Add the Sprite Asset
Place the new sprite image file (e.g., new_hat.png) into the appropriate assets directory: src/assets/character/hats/.
Step 2: Import the Sprite
In src/store/CosmeticsStore.ts, import the new sprite at the top of the file with the other hat sprites.
// src/store/CosmeticsStore.ts
import copHatSprite from '../assets/character/hats/cop_hat.png';
import crownSprite from '../assets/character/hats/crown.png';
import mexicanHatSprite from '../assets/character/hats/mexican_hat.png';
import topHatSprite from '../assets/character/hats/top_hat.png';
import newHatSprite from '../assets/character/hats/new_hat.png'; // <-- Add this line
Sources: src/store/CosmeticsStore.ts:6-9
Step 3: Update the Enum
Add a new entry to the Hats enum for your new item.
// src/store/CosmeticsStore.ts
export enum Hats {
None,
Cop,
Crown,
Mexican,
Top,
NewHat // <-- Add this line
}
Sources: src/store/CosmeticsStore.ts:37-45
Step 4: Update the Data Array
Add a new HatData object to the hatsData array, linking the new enum ID to the imported sprite.
// src/store/CosmeticsStore.ts
export const hatsData: HatData[] = [
// ... existing hat data objects
{
id: Hats.Top,
sprite: topHatSprite
},
{ // <-- Add this block
id: Hats.NewHat,
sprite: newHatSprite
}
];
Sources: src/store/CosmeticsStore.ts:47-67
After these changes, the new hat will automatically appear in the CosmeticsScreen and can be equipped by the player. No other code changes are necessary.