Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
5c4d588
Add preact and delete old UI
sorokya Apr 2, 2026
dd28172
Fix missing dom errors
sorokya Apr 2, 2026
ff61a4a
Add tailwind/daisyui
sorokya Apr 2, 2026
7efb2a2
Main menu and connection working
sorokya Apr 2, 2026
d3787ff
Refactor UI state and authentication flow; add character select/login…
sorokya Apr 3, 2026
d089e30
Wire up change password button
sorokya Apr 3, 2026
b0a6785
Add copilot instructions
sorokya Apr 3, 2026
64a3e8f
Cleanup account/character handlers
sorokya Apr 3, 2026
527b863
Change password
sorokya Apr 3, 2026
d1d2759
Change password, account creation, character creation
sorokya Apr 3, 2026
cda66b8
Reset delete confirm after delete
sorokya Apr 3, 2026
3a8d91e
In game UI round 1
sorokya Apr 4, 2026
2ef380a
refactor: clean up in-game UI code smells
sorokya Apr 4, 2026
7369894
Remove non-functional chat context menu
sorokya Apr 4, 2026
80a68dc
Second-pass in-game UI cleanup
sorokya Apr 4, 2026
2182fea
Standardize theme colors across all in-game UI
sorokya Apr 5, 2026
1d51373
Show date prefix on chat messages not from today
sorokya Apr 5, 2026
574ae31
Fix MouseController click events not firing
sorokya Apr 5, 2026
4461477
Add host input
sorokya Apr 13, 2026
e647497
Add keyboard inputs for character select
sorokya Apr 13, 2026
2e2e7c5
Fix input auto focus
sorokya Apr 13, 2026
b5c4fe8
Sort classes
sorokya Apr 13, 2026
28b2a82
feat: add weight and gold to player HUD
sorokya Apr 13, 2026
1d9f91d
feat: use react-icons for HUD stat labels
sorokya Apr 13, 2026
7ab0f39
style: cap HUD bars at max-w-40 and space evenly with justify-between
sorokya Apr 13, 2026
9501e09
Adjust hud
sorokya Apr 13, 2026
847b025
feat: inventory grid, character dialog, and item GFX loading
sorokya Apr 13, 2026
eabf0d2
Fix inventory grid & character dialog issues
sorokya Apr 13, 2026
81f836a
Fix dialog offset, equipment grid, tooltips, and formatting
sorokya Apr 13, 2026
a3ead09
Equipment slots: display items at full natural size
sorokya Apr 13, 2026
947ad9e
Equipment grid: redesign to 6-col × 8-row to match original client
sorokya Apr 13, 2026
7c5b0fa
Fix equipment grid
sorokya Apr 13, 2026
bc2c1a5
Adjust character info to match original
sorokya Apr 13, 2026
1af2f53
Format stats
sorokya Apr 13, 2026
bb292cf
Show character dialog data from paperdoll packet
sorokya Apr 13, 2026
07f767f
Change default theme
sorokya Apr 13, 2026
4d05647
Many things.. Inventory dragging and shit
sorokya Apr 13, 2026
5ba026f
Fix dropping on equipment
sorokya Apr 14, 2026
535c22d
Add UI scale
sorokya Apr 14, 2026
7b31fe0
Make all dialogs centered by default and fix doll tooltips on non pla…
sorokya Apr 14, 2026
7eb60ab
Better mobile detection. Compact hud. Idk
sorokya Apr 14, 2026
eb1952d
Improve mobile
sorokya Apr 14, 2026
088250f
Ignore click after closing chat
sorokya Apr 14, 2026
ba81ed5
Fix auto focus chat on mobile
sorokya Apr 14, 2026
54c368c
Fix item dragging on mobile
sorokya Apr 14, 2026
7633631
Touch controls
sorokya Apr 14, 2026
f5b6125
Hot bar working
sorokya Apr 14, 2026
9643d5b
UI cleanup
sorokya Apr 14, 2026
132916a
Adjust MobileNav styling
sorokya Apr 14, 2026
ccd5a1f
Add keyboard shortcuts for viewing character, inventory, and spells; …
sorokya Apr 14, 2026
a1996d3
Simplify chat
sorokya Apr 14, 2026
84e49ab
Fix chat appearance
sorokya Apr 14, 2026
5db9d76
Add sound effects for chat input focus and button click actions
sorokya Apr 14, 2026
f567431
Add chat log functionality and enhance dialog management
sorokya Apr 14, 2026
bb17791
Adjust chat db
sorokya Apr 14, 2026
47ccada
Enhance chat log functionality with pagination, filtering, and export…
sorokya Apr 15, 2026
80a55eb
Refactor Copilot instructions for clarity and completeness in UI and …
sorokya Apr 15, 2026
9e5254f
Add command palette
sorokya Apr 15, 2026
8a25628
Remove Notyf dependency and related code from Client and main files
sorokya Apr 15, 2026
c63f3f9
Implement ToastController for improved status messaging and replace s…
sorokya Apr 15, 2026
0dfff8a
Add localization support and enhance messaging for NPC interactions a…
sorokya Apr 15, 2026
f6ced82
Refactor ToastController and StatusMessages to remove ToastType depen…
sorokya Apr 15, 2026
ced95cd
Refactor chat dialog handling by removing DialogBase and simplifying …
sorokya Apr 15, 2026
8be5f42
New config dialog
sorokya Apr 16, 2026
8cdccdf
Refactor InterfaceTab to use useUiScale for scale index management
sorokya Apr 16, 2026
6f01fb0
Implement DialogArena for dynamic dialog layout and refactor dialog c…
sorokya Apr 16, 2026
519366e
Refactor dialog handling and improve layout management by introducing…
sorokya Apr 16, 2026
ef2e7b0
Refactor color usage in ProgressBar, enums, and HUD components for co…
sorokya Apr 16, 2026
1debf73
Add Howler.js for audio management and refactor audio handling in the…
sorokya Apr 16, 2026
a7449d3
Add spessasynth_lib for MIDI music playback and enhance audio handlin…
sorokya Apr 16, 2026
f248cde
Refactor AudioController to enhance MIDI initialization and error han…
sorokya Apr 16, 2026
3328695
Add sound font configuration and update AudioController to fetch spec…
sorokya Apr 16, 2026
66d27b6
Move atlas compositor to worker
sorokya Apr 16, 2026
1e861c3
Refactor MouseController to improve touch handling and add swipe dete…
sorokya Apr 16, 2026
f3ba183
Add force music loop configuration and UI toggle in SoundTab
sorokya Apr 16, 2026
fb3dd97
Add jukebox music playback functionality to AudioController and updat…
sorokya Apr 16, 2026
683f121
Implement jukebox functionality with controller, UI, and audio integr…
sorokya Apr 16, 2026
a82a023
Add Social Dialog and integrate player list functionality in SocialCo…
sorokya Apr 16, 2026
f15788d
Add storage for friends/ignore list
sorokya Apr 16, 2026
72c962b
Refactor social controller to use constants for storage keys and impr…
sorokya Apr 16, 2026
1d15985
Add localization support for chat, inventory, quests, settings, and s…
sorokya Apr 16, 2026
837651a
Add chest dialog
sorokya Apr 17, 2026
8e913c9
Chat improvements
sorokya Apr 18, 2026
3c93326
Add unsubscribe methods for paperdoll and jukebox events, and refacto…
sorokya Apr 19, 2026
7ca82f6
Move size calculations from atlas to worker
sorokya Apr 19, 2026
cc29638
Refactor inventory and chest item handling to simplify drop and junk …
sorokya Apr 19, 2026
9d96a8b
Fix HotBarSlot drag-and-drop functionality by capturing pointer event…
sorokya Apr 19, 2026
95a41fd
Enhance input handling by capturing keydown events to prevent default…
sorokya Apr 19, 2026
257b9b8
Add locker
sorokya Apr 19, 2026
76c70ac
Implement bank dialog and enhance bank controller functionality with …
sorokya Apr 19, 2026
539af5e
Add shop dialog
sorokya Apr 19, 2026
7f7851e
Refactor item slot components to use ItemIcon and improve layout; add…
sorokya Apr 19, 2026
e3657b6
Add Skill Master dialog and enhance stat skill controller with subscr…
sorokya Apr 19, 2026
02e77a6
Implement skill training, enhance spell dialog, and add junk drop zon…
sorokya Apr 19, 2026
a0a8cb6
Add chat notifications for bank, locker, shop, chest, and skill event…
sorokya Apr 19, 2026
a555568
Quests working
sorokya Apr 20, 2026
f1f6a54
Make colors consistent
sorokya Apr 20, 2026
789837d
Adjust styling for all dialogs and fix quest tracker
sorokya Apr 20, 2026
74f2764
Refactor NPC killed message handling to return null for missing data …
sorokya Apr 20, 2026
95745ae
Move inventory items to inventoryController
sorokya Apr 20, 2026
74a0591
Move inventory controller events and debounce it when items are added…
sorokya Apr 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 169 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# EOWeb – Copilot Instructions

EOWeb is a browser-based client for Endless Online (classic MMORPG, 0.0.28 protocol). It connects to game servers over WebSocket and renders the world using Pixi.js, with a Preact UI for menus/dialogs.

## Commands

```sh
pnpm dev # Vite dev server (port 3000)
pnpm build # tsc && vite build → dist/
pnpm lint # biome check .
pnpm format # biome check --write .
```

There is no test suite.

## Architecture

The app has two rendering layers that serve different purposes:

- **Preact UI** (`src/ui/`) — overlaid on the canvas at all times. For pre-game screens (main menu, login, character select, etc.) it renders full-screen containers. In the `InGame` state it renders the in-game overlay: HUD, chat, hotbar, dialogs, touch controls, etc. Conditionally rendered based on `GameState` enum.
- **Pixi.js** (`src/map.ts`, `src/atlas.ts`, `src/render/`) — handles all in-game rendering: map tiles, characters, NPCs, animations, effects.

The central object is `Client` (`src/client/client.ts`). It owns all game state, every controller, the packet bus, the Pixi.js `Application`, and the `MapRenderer`. Nearly everything receives a `Client` reference.

### Data flow

```
WebSocket → PacketBus → handlers/ → client state / emit events → UI / Pixi render
```

- **`src/bus.ts` (`PacketBus`)** — manages the WebSocket connection and dispatches incoming packets by `PacketFamily + PacketAction` to registered handler functions.
- **`src/handlers/`** — one file per packet family. Each exports a `registerXxxHandlers(client: Client)` function that calls `client.bus.registerPacketHandler(family, action, fn)`. All are registered at startup via `registerAllHandlers(client)`.
- **`src/controllers/`** — encapsulate client-side logic for sending packets and managing related state (e.g., `MovementController`, `InventoryController`). Each takes `Client` in its constructor.
- **`src/client/events.ts`** — typed `ClientEvents` map used by the mitt emitter on `Client`. Most handlers still call `client.emit(...)` and UI subscribes via `client.on(...)`, but newer controllers expose typed `subscribe*` methods (e.g. `subscribeConfirm`, `subscribePaperdollOpened`) as part of an ongoing refactor away from `ClientEvents`.

### Persistence

`src/db.ts` wraps IndexedDB (via `idb`) with three stores:
- `pubs` — serialized EIF/ENF/ECF/ESF pub files (keyed by string: `'eif'`, `'enf'`, etc.)
- `maps` — serialized EMF map files (keyed by map ID number)
- `edfs` — EDF dialog/string files (keyed by file ID); fetched from `/data/datNNN.edf` on cache miss

### Game loop

`src/main.tsx` sets up a Pixi.js ticker at 120 ms per tick:
```ts
client.tick(); // game logic
client.render(interp); // interpolated Pixi render
```

### Graphics

`src/atlas.ts` (`Atlas`) builds a dynamic texture atlas for character/NPC sprites on demand. Graphics files are loaded from `public/gfx/gfxNNN.egf` (Custom PE Files). `src/gfx/gfx-loader.worker.ts` loads and parses these files in a Web Worker.

## Key Conventions

### Imports

- **Always use `@/` path alias** — never `../` relative parent imports. This is enforced by Biome as an error.
- **Import from barrel files**, not deep paths. The following modules have barrels and must be imported from the top level:
- `@/utils`, `@/render`, `@/controllers`, `@/handlers`, `@/gfx`, `@/fonts`
- For in-game UI: `@/ui/in-game` (not `@/ui/in-game/chat/chat-manager`, etc.)
- For UI enums (`ChatTab`, `ChatIcon`, `DialogIcon`, `SlotType`, `ISlot`): import from `@/ui/enums` directly to avoid circular dependencies, not from `@/ui`

### Style

- Single quotes for JS/TS strings and JSX attributes (enforced by Biome).
- Biome (not ESLint/Prettier) is the sole linter/formatter. Run `pnpm lint` to check, `pnpm format` to auto-fix.

### Packet handlers

Register handlers in `src/handlers/<family>.ts`:
```ts
export function registerWalkHandlers(client: Client) {
client.bus!.registerPacketHandler(PacketFamily.Walk, PacketAction.Player,
(reader) => handleWalkPlayer(client, reader));
}
```
Each handler function deserializes using the corresponding `eolib` packet class: `XxxServerPacket.deserialize(reader)`.

### Controllers

Controller classes store a private `client: Client` reference. They send packets by constructing `eolib` client packet objects and calling `this.client.bus!.send(packet)`.

### Hair style

`hairStyle` is 1-based. A value of `0` means no hair. Rendering uses `(hairStyle - 1) * 40 + hairColor * 4`.

### Nullable returns

- `getEmf(id)` returns `Promise<Emf | null>` — always handle the null case.
- `client.getDialogStrings(id)` always returns a 2-element `string[]` (fallback `['', '']`).

### UI Look and Feel

The UI uses DaisyUI components with Tailwind CSS. Reference @.github/daisyui-llms.txt for component usage and styling conventions.

Shared components (e.g., `Button`) are in `src/ui/components/`. Container components for each screen are in `src/ui/containers/`.

### In game UI elements

All in-game UI elements should be movable by the player (Toggle in settings, then drag to reposition) with default
positions based on screen size.

A global UI Scale setting should allow the player to adjust the size of all UI elements (except the main game canvas) for better readability on different screen sizes.

The following elements are planned/implemented:
- Hotbar (assignable item/skill slots) (**Implemented**: `HotBar` in `src/ui/in-game/hud/hot-bar.tsx`)
- HUD (character name/level/HP/TP/TNL display (numeric & bars)) (**Implemented**: `PlayerHud` in `src/ui/in-game/hud/player-hud.tsx`)
- Side menu (inventory, map, stats, skills, quests, settings, etc.) (**Implemented**: `NavSidebar` / `MobileNav` in `src/ui/in-game/hud/nav-sidebar.tsx`)
- Collapsed to hamburger menu for mobile screens
- Touch controls (virtual joystick + buttons, shown only on mobile) (**Implemented**: `TouchJoystick` / `TouchActionButtons` in `src/ui/in-game/hud/`)
- Chat (**Implemented**: `ChatDialog` / `ChatManagerProvider` in `src/ui/in-game/chat/`)
- All messages have a name (optional), icon (optional), and text.
- The client tracks timestamp for each message and displays as local time (e.g., `[12:34:56]`).
- Chat messages are saved in IndexedDB for chat history to view/search in the Chat Log window.
- WoW style (Color coded, optionally open in separate tabs)
- Local channel (nearby characters, and npcs)
- Global channel (all players, messages prefixed with `~` to send to global)
- Group channel (party messages, prefixed with `'` to send to group)
- Guild channel (guild messages, prefixed with `&` to send to guild)
- Admin channel (GMs only, prefixed with `+` to send to admin)
- Whisper channel(s) (private messages, prefixed with `!recipientName` to send a whisper)
- System messages (Combat log, item pickups, etc. system generated)
- Dialog windows (**Partially implemented**: `src/ui/in-game/dialogs/`)
- Flex positions by default (centered with gap), but allow dragging to reposition (and save position per dialog type).
- Support multiple open dialogs at once (e.g., Inventory + Character + Quests) with proper z-index stacking when clicked.
- Implemented dialogs: `InventoryDialog`, `SpellsDialog`, `CharacterDialog` (Paperdoll), `QuestsDialog`, `SettingsDialog`, `ChatLogDialog`
- Base dialog types:
- Scrolling List
- Layout:
- Title
- Scrollable content area (e.g., list of items, quests, skills, etc.)
- Action buttons (e.g., Cancel, OK, etc.)
- Push/Pop state for nested dialogs (e.g items for sale -> list of items)
- Dialogs using this layout: Shop, Skill master, Inn keeper, Lawyer (for marriage/divorce), Guild master
- Scrolling grid:
- Layout:
- Title
- Scrollable grid content area (e.g., inventory grid, skill grid, etc.)
- Action buttons (e.g., Cancel, OK, etc.)
- Push/Pop state for nested dialogs (e.g., inventory -> item details)
- Dialogs using this layout: Chest, Locker, Skill list
- Custom Dialog Types:
- Paperdoll (**Implemented** as `CharacterDialog`)
- Displays player information and equipment
- Layout:
- Character info (name, title, home, class, partner, guild name, guild rank name, admin badge)
- Equipment slots (hat, necklace, weapon, armor, shield, gloves, belt, boots, ring 1, ring 2, armlet 1, armlet 2, bracer 1, bracer 2, accessory)
- Displayed in a grid with empty slots for unequipped items
- Image is loaded from gfx-loader
- Hovering over an equipped item shows a tooltip with item details
- OK button to close the dialog
- More to come

## Public assets

Game data files must be placed in `public/` before running:
- `public/gfx/gfxNNN.egf` — Custom PE Files for graphics (extracted via gfx-loader)
- `public/sfx/sfxNNN.wav` — sound effects
- `public/maps/NNNNN.emf` — map files (_only_ used for the title screen, in-game maps are loaded via protocol over WebSocket and cached in IndexedDB)
- `public/data/datNNN.edf` — dialog/string data files

# Refactoring notes

- Currently a lot of game state is stored in `Client`. Some things have been extracted into controllers but there's still
a lot that need to be moved out.
- The `ClientEvents` / `client.emit` pattern is being phased out in favor of controller-specific `subscribe*` methods (e.g. `subscribeConfirm`, `subscribePaperdollOpened`) that UI hooks call directly. Handlers still predominantly use `client.emit`, but new code should prefer the subscribe pattern on the relevant controller.
- The `GameState` enum has been expanded with all necessary specific states (`CharacterSelect`, `ChangePassword`, `CreateCharacter`, `InGame`, etc.) — this refactor is complete.
Loading
Loading